v7_mod_table_recheck_autovac.patch
application/octet-stream
Filename: v7_mod_table_recheck_autovac.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v7
| File | + | − |
|---|---|---|
| src/backend/postmaster/autovacuum.c | 79 | 19 |
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index aa5b97f..ac3982c 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -325,6 +325,10 @@ static void autovac_balance_cost(void);
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
+static void recheck_relation_needs_vacanalyze(Oid relid, Form_pg_class classForm,
+ AutoVacOpts *avopts,
+ int effective_multixact_freeze_max_age,
+ bool *dovacuum, bool *doanalyze, bool *wraparound);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc,
int effective_multixact_freeze_max_age);
@@ -2780,6 +2784,40 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
}
/*
+ * Subroutine of table_recheck_autovac.
+ */
+static void
+recheck_relation_needs_vacanalyze(Oid relid,
+ Form_pg_class classForm,
+ AutoVacOpts *avopts,
+ int effective_multixact_freeze_max_age,
+ bool *dovacuum,
+ bool *doanalyze,
+ bool *wraparound)
+{
+ PgStat_StatTabEntry *tabentry;
+ PgStat_StatDBEntry *shared = NULL;
+ PgStat_StatDBEntry *dbentry = NULL;
+
+ if (classForm->relisshared)
+ shared = pgstat_fetch_stat_dbentry(InvalidOid);
+ else
+ dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
+
+ /* fetch the pgstat table entry */
+ tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
+ shared, dbentry);
+
+ relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
+ effective_multixact_freeze_max_age,
+ dovacuum, doanalyze, wraparound);
+
+ /* ignore ANALYZE for toast tables */
+ if (classForm->relkind == RELKIND_TOASTVALUE)
+ *doanalyze = false;
+}
+
+/*
* table_recheck_autovac
*
* Recheck whether a table still needs vacuum or analyze. Return value is a
@@ -2797,17 +2835,9 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
- PgStat_StatTabEntry *tabentry;
- PgStat_StatDBEntry *shared;
- PgStat_StatDBEntry *dbentry;
bool wraparound;
AutoVacOpts *avopts;
-
- /* use fresh stats */
- autovac_refresh_stats();
-
- shared = pgstat_fetch_stat_dbentry(InvalidOid);
- dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
+ static bool use_existing_stats = false;
/* fetch the relation's relcache entry */
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2831,17 +2861,33 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
avopts = &hentry->ar_reloptions;
}
- /* fetch the pgstat table entry */
- tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
- shared, dbentry);
+ /*
+ * Before stats refresh, check existing stats for avoiding frequent reloading
+ * of pgstats if possible.
+ * In the case of very large numbers of tables, the cost of re-reading
+ * the stats file can be significant, and the frequent calls to
+ * autovac_refresh_stats() can make certain autovacuum workers unable to work.
+ */
+ if (use_existing_stats)
+ {
+ recheck_relation_needs_vacanalyze(relid, classForm, avopts,
+ effective_multixact_freeze_max_age,
+ &dovacuum, &doanalyze, &wraparound);
- relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
- effective_multixact_freeze_max_age,
- &dovacuum, &doanalyze, &wraparound);
+ /* someone has already issued vacuum, so exit quickly */
+ if (!doanalyze && !dovacuum)
+ {
+ heap_freetuple(classTup);
+ return NULL;
+ }
+ }
- /* ignore ANALYZE for toast tables */
- if (classForm->relkind == RELKIND_TOASTVALUE)
- doanalyze = false;
+ /* use fresh stats and recheck again */
+ autovac_refresh_stats();
+
+ recheck_relation_needs_vacanalyze(relid, classForm, avopts,
+ effective_multixact_freeze_max_age,
+ &dovacuum, &doanalyze, &wraparound);
/* OK, it needs something done */
if (doanalyze || dovacuum)
@@ -2929,10 +2975,24 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
tab->at_dobalance =
!(avopts && (avopts->vacuum_cost_limit > 0 ||
avopts->vacuum_cost_delay > 0));
+
+ /*
+ * When we decide to do vacuum or analyze, the existing stats cannot
+ * be reused in the next cycle because it's cleared at the end of vacuum
+ * or analyze (by AtEOXact_PgStat()).
+ */
+ use_existing_stats = false;
+ }
+ else
+ {
+ /*
+ * If neither vacuum nor analyze is necessary, the existing stats is
+ * not cleared and can be reused in the next cycle.
+ */
+ use_existing_stats = true;
}
heap_freetuple(classTup);
-
return tab;
}