Simplify state managed by VACUUM.

Reorganize the state struct used by VACUUM -- group related items
together to make it easier to understand.  Also stop relying on stack
variables inside lazy_scan_heap() -- move those into the state struct
instead.  Doing things this way simplifies large groups of related
functions whose function signatures had a lot of unnecessary redundancy.

Switch over to using int64 for the struct fields used to count things
that are reported to the user via log_autovacuum and VACUUM VERBOSE
output.  We were using double, but that doesn't seem to have any
advantages.  Using int64 makes it possible to add assertions that verify
that the first pass over the heap (pruning) encounters precisely the
same number of LP_DEAD items that get deleted from indexes later on, in
the second pass over the heap.  These assertions will be added in later
commits.

Finally, adjust the signatures of functions with IndexBulkDeleteResult
pointer arguments in cases where there was ambiguity about whether or
not the argument relates to a single index or all indexes.  Functions
now use the idiom that both ambulkdelete() and amvacuumcleanup() have
always used (where appropriate): accept a mutable IndexBulkDeleteResult
pointer argument, and return a result IndexBulkDeleteResult pointer to
caller.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-By: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/CAH2-WzkeOSYwC6KNckbhk2b1aNnWum6Yyn0NKP9D-Hq1LGTDPw@mail.gmail.com
This commit is contained in:
Peter Geoghegan 2021-04-05 13:21:44 -07:00
parent 6c3ffd697e
commit b4af70cb21
6 changed files with 813 additions and 719 deletions

File diff suppressed because it is too large Load Diff

View File

@ -689,7 +689,7 @@ index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
*/ */
IndexBulkDeleteResult * IndexBulkDeleteResult *
index_bulk_delete(IndexVacuumInfo *info, index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats, IndexBulkDeleteResult *istat,
IndexBulkDeleteCallback callback, IndexBulkDeleteCallback callback,
void *callback_state) void *callback_state)
{ {
@ -698,7 +698,7 @@ index_bulk_delete(IndexVacuumInfo *info,
RELATION_CHECKS; RELATION_CHECKS;
CHECK_REL_PROCEDURE(ambulkdelete); CHECK_REL_PROCEDURE(ambulkdelete);
return indexRelation->rd_indam->ambulkdelete(info, stats, return indexRelation->rd_indam->ambulkdelete(info, istat,
callback, callback_state); callback, callback_state);
} }
@ -710,14 +710,14 @@ index_bulk_delete(IndexVacuumInfo *info,
*/ */
IndexBulkDeleteResult * IndexBulkDeleteResult *
index_vacuum_cleanup(IndexVacuumInfo *info, index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats) IndexBulkDeleteResult *istat)
{ {
Relation indexRelation = info->index; Relation indexRelation = info->index;
RELATION_CHECKS; RELATION_CHECKS;
CHECK_REL_PROCEDURE(amvacuumcleanup); CHECK_REL_PROCEDURE(amvacuumcleanup);
return indexRelation->rd_indam->amvacuumcleanup(info, stats); return indexRelation->rd_indam->amvacuumcleanup(info, istat);
} }
/* ---------------- /* ----------------

View File

@ -617,7 +617,7 @@ Relation
vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options, vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options,
bool verbose, LOCKMODE lmode) bool verbose, LOCKMODE lmode)
{ {
Relation onerel; Relation rel;
bool rel_lock = true; bool rel_lock = true;
int elevel; int elevel;
@ -633,18 +633,18 @@ vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options,
* in non-blocking mode, before calling try_relation_open(). * in non-blocking mode, before calling try_relation_open().
*/ */
if (!(options & VACOPT_SKIP_LOCKED)) if (!(options & VACOPT_SKIP_LOCKED))
onerel = try_relation_open(relid, lmode); rel = try_relation_open(relid, lmode);
else if (ConditionalLockRelationOid(relid, lmode)) else if (ConditionalLockRelationOid(relid, lmode))
onerel = try_relation_open(relid, NoLock); rel = try_relation_open(relid, NoLock);
else else
{ {
onerel = NULL; rel = NULL;
rel_lock = false; rel_lock = false;
} }
/* if relation is opened, leave */ /* if relation is opened, leave */
if (onerel) if (rel)
return onerel; return rel;
/* /*
* Relation could not be opened, hence generate if possible a log * Relation could not be opened, hence generate if possible a log
@ -1726,8 +1726,8 @@ static bool
vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
{ {
LOCKMODE lmode; LOCKMODE lmode;
Relation onerel; Relation rel;
LockRelId onerelid; LockRelId lockrelid;
Oid toast_relid; Oid toast_relid;
Oid save_userid; Oid save_userid;
int save_sec_context; int save_sec_context;
@ -1792,11 +1792,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
AccessExclusiveLock : ShareUpdateExclusiveLock; AccessExclusiveLock : ShareUpdateExclusiveLock;
/* open the relation and get the appropriate lock on it */ /* open the relation and get the appropriate lock on it */
onerel = vacuum_open_relation(relid, relation, params->options, rel = vacuum_open_relation(relid, relation, params->options,
params->log_min_duration >= 0, lmode); params->log_min_duration >= 0, lmode);
/* leave if relation could not be opened or locked */ /* leave if relation could not be opened or locked */
if (!onerel) if (!rel)
{ {
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
@ -1811,11 +1811,11 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* changed in-between. Make sure to only generate logs for VACUUM in this * changed in-between. Make sure to only generate logs for VACUUM in this
* case. * case.
*/ */
if (!vacuum_is_relation_owner(RelationGetRelid(onerel), if (!vacuum_is_relation_owner(RelationGetRelid(rel),
onerel->rd_rel, rel->rd_rel,
params->options & VACOPT_VACUUM)) params->options & VACOPT_VACUUM))
{ {
relation_close(onerel, lmode); relation_close(rel, lmode);
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return false; return false;
@ -1824,15 +1824,15 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
/* /*
* Check that it's of a vacuumable relkind. * Check that it's of a vacuumable relkind.
*/ */
if (onerel->rd_rel->relkind != RELKIND_RELATION && if (rel->rd_rel->relkind != RELKIND_RELATION &&
onerel->rd_rel->relkind != RELKIND_MATVIEW && rel->rd_rel->relkind != RELKIND_MATVIEW &&
onerel->rd_rel->relkind != RELKIND_TOASTVALUE && rel->rd_rel->relkind != RELKIND_TOASTVALUE &&
onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{ {
ereport(WARNING, ereport(WARNING,
(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables", (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
RelationGetRelationName(onerel)))); RelationGetRelationName(rel))));
relation_close(onerel, lmode); relation_close(rel, lmode);
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return false; return false;
@ -1845,9 +1845,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* warning here; it would just lead to chatter during a database-wide * warning here; it would just lead to chatter during a database-wide
* VACUUM.) * VACUUM.)
*/ */
if (RELATION_IS_OTHER_TEMP(onerel)) if (RELATION_IS_OTHER_TEMP(rel))
{ {
relation_close(onerel, lmode); relation_close(rel, lmode);
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return false; return false;
@ -1858,9 +1858,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* useful work is on their child partitions, which have been queued up for * useful work is on their child partitions, which have been queued up for
* us separately. * us separately.
*/ */
if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{ {
relation_close(onerel, lmode); relation_close(rel, lmode);
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
/* It's OK to proceed with ANALYZE on this table */ /* It's OK to proceed with ANALYZE on this table */
@ -1877,14 +1877,14 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* because the lock manager knows that both lock requests are from the * because the lock manager knows that both lock requests are from the
* same process. * same process.
*/ */
onerelid = onerel->rd_lockInfo.lockRelId; lockrelid = rel->rd_lockInfo.lockRelId;
LockRelationIdForSession(&onerelid, lmode); LockRelationIdForSession(&lockrelid, lmode);
/* Set index cleanup option based on reloptions if not yet */ /* Set index cleanup option based on reloptions if not yet */
if (params->index_cleanup == VACOPT_TERNARY_DEFAULT) if (params->index_cleanup == VACOPT_TERNARY_DEFAULT)
{ {
if (onerel->rd_options == NULL || if (rel->rd_options == NULL ||
((StdRdOptions *) onerel->rd_options)->vacuum_index_cleanup) ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup)
params->index_cleanup = VACOPT_TERNARY_ENABLED; params->index_cleanup = VACOPT_TERNARY_ENABLED;
else else
params->index_cleanup = VACOPT_TERNARY_DISABLED; params->index_cleanup = VACOPT_TERNARY_DISABLED;
@ -1893,8 +1893,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
/* Set truncate option based on reloptions if not yet */ /* Set truncate option based on reloptions if not yet */
if (params->truncate == VACOPT_TERNARY_DEFAULT) if (params->truncate == VACOPT_TERNARY_DEFAULT)
{ {
if (onerel->rd_options == NULL || if (rel->rd_options == NULL ||
((StdRdOptions *) onerel->rd_options)->vacuum_truncate) ((StdRdOptions *) rel->rd_options)->vacuum_truncate)
params->truncate = VACOPT_TERNARY_ENABLED; params->truncate = VACOPT_TERNARY_ENABLED;
else else
params->truncate = VACOPT_TERNARY_DISABLED; params->truncate = VACOPT_TERNARY_DISABLED;
@ -1907,7 +1907,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
*/ */
if ((params->options & VACOPT_PROCESS_TOAST) != 0 && if ((params->options & VACOPT_PROCESS_TOAST) != 0 &&
(params->options & VACOPT_FULL) == 0) (params->options & VACOPT_FULL) == 0)
toast_relid = onerel->rd_rel->reltoastrelid; toast_relid = rel->rd_rel->reltoastrelid;
else else
toast_relid = InvalidOid; toast_relid = InvalidOid;
@ -1918,7 +1918,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* unnecessary, but harmless, for lazy VACUUM.) * unnecessary, but harmless, for lazy VACUUM.)
*/ */
GetUserIdAndSecContext(&save_userid, &save_sec_context); GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner, SetUserIdAndSecContext(rel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION); save_sec_context | SECURITY_RESTRICTED_OPERATION);
save_nestlevel = NewGUCNestLevel(); save_nestlevel = NewGUCNestLevel();
@ -1930,8 +1930,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
ClusterParams cluster_params = {0}; ClusterParams cluster_params = {0};
/* close relation before vacuuming, but hold lock until commit */ /* close relation before vacuuming, but hold lock until commit */
relation_close(onerel, NoLock); relation_close(rel, NoLock);
onerel = NULL; rel = NULL;
if ((params->options & VACOPT_VERBOSE) != 0) if ((params->options & VACOPT_VERBOSE) != 0)
cluster_params.options |= CLUOPT_VERBOSE; cluster_params.options |= CLUOPT_VERBOSE;
@ -1940,7 +1940,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
cluster_rel(relid, InvalidOid, &cluster_params); cluster_rel(relid, InvalidOid, &cluster_params);
} }
else else
table_relation_vacuum(onerel, params, vac_strategy); table_relation_vacuum(rel, params, vac_strategy);
/* Roll back any GUC changes executed by index functions */ /* Roll back any GUC changes executed by index functions */
AtEOXact_GUC(false, save_nestlevel); AtEOXact_GUC(false, save_nestlevel);
@ -1949,8 +1949,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
SetUserIdAndSecContext(save_userid, save_sec_context); SetUserIdAndSecContext(save_userid, save_sec_context);
/* all done with this class, but hold lock until commit */ /* all done with this class, but hold lock until commit */
if (onerel) if (rel)
relation_close(onerel, NoLock); relation_close(rel, NoLock);
/* /*
* Complete the transaction and free all temporary memory used. * Complete the transaction and free all temporary memory used.
@ -1971,7 +1971,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
/* /*
* Now release the session-level lock on the main table. * Now release the session-level lock on the main table.
*/ */
UnlockRelationIdForSession(&onerelid, lmode); UnlockRelationIdForSession(&lockrelid, lmode);
/* Report that we really did it. */ /* Report that we really did it. */
return true; return true;

View File

@ -177,11 +177,11 @@ extern bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction,
extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap); extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info, extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats, IndexBulkDeleteResult *istat,
IndexBulkDeleteCallback callback, IndexBulkDeleteCallback callback,
void *callback_state); void *callback_state);
extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info, extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats); IndexBulkDeleteResult *istat);
extern bool index_can_return(Relation indexRelation, int attno); extern bool index_can_return(Relation indexRelation, int attno);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum); uint16 procnum);

View File

@ -196,7 +196,7 @@ extern void heap_get_root_tuples(Page page, OffsetNumber *root_offsets);
/* in heap/vacuumlazy.c */ /* in heap/vacuumlazy.c */
struct VacuumParams; struct VacuumParams;
extern void heap_vacuum_rel(Relation onerel, extern void heap_vacuum_rel(Relation rel,
struct VacuumParams *params, BufferAccessStrategy bstrategy); struct VacuumParams *params, BufferAccessStrategy bstrategy);
extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc); extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc);

View File

@ -625,7 +625,7 @@ typedef struct TableAmRoutine
* There probably, in the future, needs to be a separate callback to * There probably, in the future, needs to be a separate callback to
* integrate with autovacuum's scheduling. * integrate with autovacuum's scheduling.
*/ */
void (*relation_vacuum) (Relation onerel, void (*relation_vacuum) (Relation rel,
struct VacuumParams *params, struct VacuumParams *params,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);