diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index faa181207a..4031fae57d 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -67,7 +67,7 @@ static BufferAccessStrategy vac_strategy; /* non-export function prototypes */ -static List *get_rel_oids(Oid relid, const RangeVar *vacrel); +static List *get_rel_oids(Oid *relid, const RangeVar *vacrel); static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, @@ -129,8 +129,12 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) * options is a bitmask of VacuumOption flags, indicating what to do. * * relid, if not InvalidOid, indicate the relation to process; otherwise, - * the RangeVar is used. (The latter must always be passed, because it's - * used for error messages.) + * the RangeVar is used. The latter must be passed because it is used + * for error reporting, still it will not be used for relations vacuumed + * which have been dragged into the process due to inheritance, like + * child partitions. Note that RangeVar is NULL if relid is InvalidOid, + * which happens in the case of manual VACUUM commands not specifying a + * list of relations. * * params contains a set of parameters that can be used to customize the * behavior. @@ -229,7 +233,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, * Build list of relations to process, unless caller gave us one. (If we * build one, we put it in vac_context for safekeeping.) */ - relations = get_rel_oids(relid, relation); + relations = get_rel_oids(&relid, relation); /* * Decide whether we need to start/commit our own transactions. @@ -297,11 +301,48 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, */ foreach(cur, relations) { - Oid relid = lfirst_oid(cur); + Oid proc_relid = lfirst_oid(cur); + RangeVar *rv; + + /* + * Determine which RangeVar to use for reporting should the + * relation referenced by the OID listed here should be + * missing. + */ + if (IsAutoVacuumWorkerProcess()) + { + /* + * Autovacuum workers work on a pre-relation basis, so there + * is always a RangeVar to rely on + */ + Assert(relation != NULL); + rv = relation; + } + else if (relation) + { + /* + * A manual command is being run with a relation specified. + * Be careful that the relation being processed here may + * be a partitioned table, in which case the RangeVar + * specified by caller can only be used if the relation + * processed here is the parent itself. Hence check if the + * relation being processed is the original relation itself + * and use its RangeVar if those are the same. + */ + rv = proc_relid == relid ? relation : NULL; + } + else + { + /* + * This is the case of a manual command which does not specify + * a relation to work on, so just use nothing. + */ + rv = NULL; + } if (options & VACOPT_VACUUM) { - if (!vacuum_rel(relid, relation, options, params)) + if (!vacuum_rel(proc_relid, rv, options, params)) continue; } @@ -318,7 +359,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, PushActiveSnapshot(GetTransactionSnapshot()); } - analyze_rel(relid, relation, options, params, + analyze_rel(proc_relid, rv, options, params, va_cols, in_outer_xact, vac_strategy); if (use_own_xacts) @@ -376,29 +417,36 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, * Build a list of Oids for each relation to be processed * * The list is built in vac_context so that it will survive across our - * per-relation transactions. + * per-relation transactions. If relid is defined as InvalidOid by the + * caller, then it gets filled with the OID of the parent relation + * used for the potential inheritance scanning for partitioned tables. */ static List * -get_rel_oids(Oid relid, const RangeVar *vacrel) +get_rel_oids(Oid *relid, const RangeVar *vacrel) { List *oid_list = NIL; MemoryContext oldcontext; /* OID supplied by VACUUM's caller? */ - if (OidIsValid(relid)) + if (OidIsValid(*relid)) { + /* normal course of events for an autovacuum worker */ + Assert(IsAutoVacuumWorkerProcess()); oldcontext = MemoryContextSwitchTo(vac_context); - oid_list = lappend_oid(oid_list, relid); + oid_list = lappend_oid(oid_list, *relid); MemoryContextSwitchTo(oldcontext); } else if (vacrel) { /* Process a specific relation */ - Oid relid; + Oid parentoid; HeapTuple tuple; Form_pg_class classForm; bool include_parts; + /* manual VACUUM running here */ + Assert(!IsAutoVacuumWorkerProcess()); + /* * Since we don't take a lock here, the relation might be gone, or the * RangeVar might no longer refer to the OID we look up here. In the @@ -408,15 +456,15 @@ get_rel_oids(Oid relid, const RangeVar *vacrel) * going to commit this transaction and begin a new one between now * and then. */ - relid = RangeVarGetRelid(vacrel, NoLock, false); + parentoid = RangeVarGetRelid(vacrel, NoLock, false); /* * To check whether the relation is a partitioned table, fetch its * syscache entry. */ - tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(parentoid)); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", relid); + elog(ERROR, "cache lookup failed for relation %u", parentoid); classForm = (Form_pg_class) GETSTRUCT(tuple); include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE); ReleaseSysCache(tuple); @@ -430,10 +478,12 @@ get_rel_oids(Oid relid, const RangeVar *vacrel) oldcontext = MemoryContextSwitchTo(vac_context); if (include_parts) oid_list = list_concat(oid_list, - find_all_inheritors(relid, NoLock, NULL)); + find_all_inheritors(parentoid, NoLock, NULL)); else - oid_list = lappend_oid(oid_list, relid); + oid_list = lappend_oid(oid_list, parentoid); MemoryContextSwitchTo(oldcontext); + + *relid = parentoid; } else { @@ -445,6 +495,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel) HeapScanDesc scan; HeapTuple tuple; + /* manual vacuum running here */ + Assert(!IsAutoVacuumWorkerProcess()); + pgclass = heap_open(RelationRelationId, AccessShareLock); scan = heap_beginscan_catalog(pgclass, 0, NULL);