=== Applying patches on top of PostgreSQL commit ID a78cf591a3f5288aa5ae96902a36e342a3178b79 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sun Apr 12 22:38:26 UTC 2026 On branch cf/5839 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-autovac-save-all-relopts-instead-of-just-avopts.patch === Applying: autovac: save all relopts instead of just avopts Using index info to reconstruct a base tree... M src/backend/postmaster/autovacuum.c Falling back to patching base and 3-way merge... Auto-merging src/backend/postmaster/autovacuum.c CONFLICT (content): Merge conflict in src/backend/postmaster/autovacuum.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 autovac: save all relopts instead of just avopts When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v1-0001-autovac-save-all-relopts-instead-of-just-avopts.patch === patching file src/backend/postmaster/autovacuum.c Hunk #1 succeeded at 202 (offset 10 lines). Hunk #2 FAILED at 333. Hunk #3 succeeded at 390 (offset 45 lines). Hunk #4 FAILED at 1993. Hunk #5 FAILED at 2031. Hunk #6 succeeded at 2114 (offset 47 lines). Hunk #7 succeeded at 2137 with fuzz 2 (offset 44 lines). Hunk #8 succeeded at 2156 (offset 45 lines). Hunk #9 FAILED at 2699. Hunk #10 FAILED at 2751. Hunk #11 succeeded at 2838 (offset 74 lines). Hunk #12 FAILED at 2775. Hunk #13 FAILED at 2790. Hunk #14 succeeded at 2978 (offset 101 lines). Hunk #15 FAILED at 2893. Hunk #16 FAILED at 2906. Hunk #17 succeeded at 2991 with fuzz 2 (offset 65 lines). Hunk #18 succeeded at 3065 with fuzz 2 (offset 105 lines). Hunk #19 FAILED at 2971. Hunk #20 FAILED at 3008. 11 out of 20 hunks FAILED -- saving rejects to file src/backend/postmaster/autovacuum.c.rej Unstaged changes after reset: M src/backend/postmaster/autovacuum.c Removing src/backend/postmaster/autovacuum.c.rej === using 'git apply' to apply patch ./v1-0001-autovac-save-all-relopts-instead-of-just-avopts.patch === Applied patch to 'src/backend/postmaster/autovacuum.c' with conflicts. U src/backend/postmaster/autovacuum.c diff --cc src/backend/postmaster/autovacuum.c index 82061247988,f86c9fed853..00000000000 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@@ -381,12 -333,15 +381,20 @@@ static void FreeWorkerInfo(int code, Da static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map, TupleDesc pg_class_desc, int effective_multixact_freeze_max_age); ++<<<<<<< ours +static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts, ++======= + static void recheck_relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts, + Form_pg_class classForm, + int effective_multixact_freeze_max_age, + bool *dovacuum, bool *doanalyze, bool *wraparound); + static void relation_needs_vacanalyze(Oid relid, StdRdOptions *relopts, ++>>>>>>> theirs Form_pg_class classForm, - PgStat_StatTabEntry *tabentry, int effective_multixact_freeze_max_age, - bool *dovacuum, bool *doanalyze, bool *wraparound); + int elevel, + bool *dovacuum, bool *doanalyze, bool *wraparound, + AutoVacuumScores *scores); static void autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy); @@@ -2035,7 -1992,8 +2041,12 @@@ do_autovacuum(void while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); ++<<<<<<< ours + AutoVacOpts *relopts; ++======= + PgStat_StatTabEntry *tabentry; + StdRdOptions *relopts; ++>>>>>>> theirs Oid relid; bool dovacuum; bool doanalyze; @@@ -2074,24 -2031,18 +2085,30 @@@ } /* Fetch reloptions and the pgstat entry for this table */ ++<<<<<<< ours + relopts = extract_autovac_opts(tuple, pg_class_desc); ++======= + relopts = (StdRdOptions *) extractRelOptions(tuple, pg_class_desc, NULL); + tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared, + relid); ++>>>>>>> theirs /* Check if it needs vacuum or analyze */ - relation_needs_vacanalyze(relid, relopts, classForm, tabentry, + relation_needs_vacanalyze(relid, relopts, classForm, effective_multixact_freeze_max_age, - &dovacuum, &doanalyze, &wraparound); + DEBUG3, + &dovacuum, &doanalyze, &wraparound, + &scores); - /* Relations that need work are added to table_oids */ + /* Relations that need work are added to tables_to_process */ if (dovacuum || doanalyze) - table_oids = lappend_oid(table_oids, relid); + { + TableToProcess *table = palloc_object(TableToProcess); + + table->oid = relid; + table->score = scores.max; + tables_to_process = lappend(tables_to_process, table); + } /* * Remember TOAST associations for the second pass. Note: we must do @@@ -2138,8 -2091,9 +2155,8 @@@ while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) { Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); - PgStat_StatTabEntry *tabentry; Oid relid; - AutoVacOpts *relopts; + StdRdOptions *relopts; bool free_relopts = false; bool dovacuum; bool doanalyze; @@@ -2775,39 -2700,6 +2792,42 @@@ deleted2 } /* ++<<<<<<< ours + * extract_autovac_opts + * + * Given a relation's pg_class tuple, return a palloc'd copy of the + * AutoVacOpts portion of reloptions, if set; otherwise, return NULL. + * + * Note: callers do not have a relation lock on the table at this point, + * so the table could have been dropped, and its catalog rows gone, after + * we acquired the pg_class row. If pg_class had a TOAST table, this would + * be a risk; fortunately, it doesn't. + */ +static AutoVacOpts * +extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc) +{ + bytea *relopts; + AutoVacOpts *av; + + Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION || + ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW || + ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE); + + relopts = extractRelOptions(tup, pg_class_desc, NULL); + if (relopts == NULL) + return NULL; + + av = palloc_object(AutoVacOpts); + memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts)); + pfree(relopts); + + return av; +} + + +/* ++======= ++>>>>>>> theirs * table_recheck_autovac * * Recheck whether a table still needs vacuum or analyze. Return value is a @@@ -2826,9 -2718,8 +2846,14 @@@ table_recheck_autovac(Oid relid, HTAB * bool doanalyze; autovac_table *tab = NULL; bool wraparound; ++<<<<<<< ours + AutoVacOpts *avopts; + bool free_avopts = false; + AutoVacuumScores scores; ++======= + StdRdOptions *relopts; + bool free_relopts = false; ++>>>>>>> theirs /* fetch the relation's relcache entry */ classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); @@@ -2851,14 -2742,12 +2876,20 @@@ hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found); if (found && hentry->ar_hasrelopts) - avopts = &hentry->ar_reloptions; + relopts = &hentry->ar_reloptions; } ++<<<<<<< ours + relation_needs_vacanalyze(relid, avopts, classForm, + effective_multixact_freeze_max_age, + DEBUG3, + &dovacuum, &doanalyze, &wraparound, + &scores); ++======= + recheck_relation_needs_vacanalyze(relid, relopts, classForm, + effective_multixact_freeze_max_age, + &dovacuum, &doanalyze, &wraparound); ++>>>>>>> theirs /* OK, it needs something done */ if (doanalyze || dovacuum) @@@ -2867,8 -2756,8 +2898,13 @@@ int freeze_table_age; int multixact_freeze_min_age; int multixact_freeze_table_age; ++<<<<<<< ours + int log_vacuum_min_duration; + int log_analyze_min_duration; ++======= + int log_min_duration; + AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL); ++>>>>>>> theirs /* * Calculate the vacuum cost parameters and the freeze ages. If there @@@ -2987,15 -2852,52 +3023,54 @@@ } /* ++<<<<<<< ours ++======= + * recheck_relation_needs_vacanalyze + * + * Subroutine for table_recheck_autovac. + * + * Fetch the pgstat of a relation and recheck whether a relation + * needs to be vacuumed or analyzed. + */ + static void + recheck_relation_needs_vacanalyze(Oid relid, + StdRdOptions *relopts, + Form_pg_class classForm, + int effective_multixact_freeze_max_age, + bool *dovacuum, + bool *doanalyze, + bool *wraparound) + { + PgStat_StatTabEntry *tabentry; + + /* fetch the pgstat table entry */ + tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared, + relid); + + relation_needs_vacanalyze(relid, relopts, classForm, tabentry, + effective_multixact_freeze_max_age, + dovacuum, doanalyze, wraparound); + + /* Release tabentry to avoid leakage */ + if (tabentry) + pfree(tabentry); + + /* ignore ANALYZE for toast tables */ + if (classForm->relkind == RELKIND_TOASTVALUE) + *doanalyze = false; + } + + /* ++>>>>>>> theirs * relation_needs_vacanalyze * * Check whether a relation needs to be vacuumed or analyzed; return each into * "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is * being forced because of Xid or multixact wraparound. * - * relopts is a pointer to the AutoVacOpts options (either for itself in the + * relopts is a pointer to the StdRdOptions options (either for itself in the * case of a plain table, or for either itself or its parent table in the case - * of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be - * NULL. + * of a TOAST table), NULL if none. * * A table needs to be vacuumed if the number of dead tuples exceeds a * threshold. This threshold is calculated as @@@ -3067,20 -2928,18 +3142,24 @@@ */ static void relation_needs_vacanalyze(Oid relid, - AutoVacOpts *relopts, + StdRdOptions *relopts, Form_pg_class classForm, - PgStat_StatTabEntry *tabentry, int effective_multixact_freeze_max_age, + int elevel, /* output params below */ bool *dovacuum, bool *doanalyze, - bool *wraparound) + bool *wraparound, + AutoVacuumScores *scores) { + PgStat_StatTabEntry *tabentry; bool force_vacuum; bool av_enabled; ++<<<<<<< ours + bool may_free = false; ++======= + AutoVacOpts *avopts = (relopts ? &relopts->autovacuum : NULL); ++>>>>>>> theirs /* constants from reloptions or GUC variables */ int vac_base_thresh, @@@ -3150,31 -2995,27 +3229,35 @@@ : autovacuum_vac_ins_scale; /* -1 is used to disable insert vacuums */ - vac_ins_base_thresh = (relopts && relopts->vacuum_ins_threshold >= -1) - ? relopts->vacuum_ins_threshold + vac_ins_base_thresh = (avopts && avopts->vacuum_ins_threshold >= -1) + ? avopts->vacuum_ins_threshold : autovacuum_vac_ins_thresh; - anl_scale_factor = (relopts && relopts->analyze_scale_factor >= 0) - ? relopts->analyze_scale_factor + anl_scale_factor = (avopts && avopts->analyze_scale_factor >= 0) + ? avopts->analyze_scale_factor : autovacuum_anl_scale; - anl_base_thresh = (relopts && relopts->analyze_threshold >= 0) - ? relopts->analyze_threshold + anl_base_thresh = (avopts && avopts->analyze_threshold >= 0) + ? avopts->analyze_threshold : autovacuum_anl_thresh; - freeze_max_age = (relopts && relopts->freeze_max_age >= 0) - ? Min(relopts->freeze_max_age, autovacuum_freeze_max_age) + freeze_max_age = (avopts && avopts->freeze_max_age >= 0) + ? Min(avopts->freeze_max_age, autovacuum_freeze_max_age) : autovacuum_freeze_max_age; - multixact_freeze_max_age = (relopts && relopts->multixact_freeze_max_age >= 0) - ? Min(relopts->multixact_freeze_max_age, effective_multixact_freeze_max_age) + multixact_freeze_max_age = (avopts && avopts->multixact_freeze_max_age >= 0) + ? Min(avopts->multixact_freeze_max_age, effective_multixact_freeze_max_age) : effective_multixact_freeze_max_age; ++<<<<<<< ours + av_enabled = (relopts ? relopts->enabled : true); + av_enabled &= AutoVacuumingActive(); + + relfrozenxid = classForm->relfrozenxid; + relminmxid = classForm->relminmxid; ++======= + av_enabled = (avopts ? avopts->enabled : true); ++>>>>>>> theirs /* Force vacuum if table is at risk of wraparound */ xidForceLimit = recentXid - freeze_max_age;