mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Refactor relation opening for VACUUM and ANALYZE
VACUUM and ANALYZE share similar logic when it comes to opening a relation to work on in terms of how the relation is opened, in which order locks are tried and how logs should be generated when something does not work as expected. This commit refactors things so as both use the same code path to handle the way a relation is opened, so as the integration of new options becomes easier. Author: Michael Paquier Reviewed-by: Nathan Bossart Discussion: https://postgr.es/m/20180927075152.GT1659@paquier.xyz
This commit is contained in:
parent
cf3dfea45b
commit
e3a25ab9ea
@ -120,7 +120,6 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
|
||||
int elevel;
|
||||
AcquireSampleRowsFunc acquirefunc = NULL;
|
||||
BlockNumber relpages = 0;
|
||||
bool rel_lock = true;
|
||||
|
||||
/* Select logging level */
|
||||
if (options & VACOPT_VERBOSE)
|
||||
@ -142,58 +141,16 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
|
||||
* concurrent VACUUM, which doesn't matter much at the moment but might
|
||||
* matter if we ever try to accumulate stats on dead tuples.) If the rel
|
||||
* has been dropped since we last saw it, we don't need to process it.
|
||||
*
|
||||
* Make sure to generate only logs for ANALYZE in this case.
|
||||
*/
|
||||
if (!(options & VACOPT_SKIP_LOCKED))
|
||||
onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
|
||||
else if (ConditionalLockRelationOid(relid, ShareUpdateExclusiveLock))
|
||||
onerel = try_relation_open(relid, NoLock);
|
||||
else
|
||||
{
|
||||
onerel = NULL;
|
||||
rel_lock = false;
|
||||
}
|
||||
onerel = vacuum_open_relation(relid, relation, params,
|
||||
options & ~(VACOPT_VACUUM),
|
||||
ShareUpdateExclusiveLock);
|
||||
|
||||
/*
|
||||
* If we failed to open or lock the relation, emit a log message before
|
||||
* exiting.
|
||||
*/
|
||||
/* leave if relation could not be opened or locked */
|
||||
if (!onerel)
|
||||
{
|
||||
/*
|
||||
* If the RangeVar is not defined, we do not have enough information
|
||||
* to provide a meaningful log statement. Chances are that
|
||||
* analyze_rel's caller has intentionally not provided this
|
||||
* information so that this logging is skipped, anyway.
|
||||
*/
|
||||
if (relation == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Determine the log level. For autovacuum logs, we emit a LOG if
|
||||
* log_autovacuum_min_duration is not disabled. For manual ANALYZE,
|
||||
* we emit a WARNING to match the log statements in the permissions
|
||||
* checks.
|
||||
*/
|
||||
if (!IsAutoVacuumWorkerProcess())
|
||||
elevel = WARNING;
|
||||
else if (params->log_min_duration >= 0)
|
||||
elevel = LOG;
|
||||
else
|
||||
return;
|
||||
|
||||
if (!rel_lock)
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||
errmsg("skipping analyze of \"%s\" --- lock not available",
|
||||
relation->relname)));
|
||||
else
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("skipping analyze of \"%s\" --- relation no longer exists",
|
||||
relation->relname)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if relation needs to be skipped based on ownership. This check
|
||||
|
@ -482,6 +482,112 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vacuum_open_relation
|
||||
*
|
||||
* This routine is used for attempting to open and lock a relation which
|
||||
* is going to be vacuumed or analyzed. If the relation cannot be opened
|
||||
* or locked, a log is emitted if possible.
|
||||
*/
|
||||
Relation
|
||||
vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params,
|
||||
int options, LOCKMODE lmode)
|
||||
{
|
||||
Relation onerel;
|
||||
bool rel_lock = true;
|
||||
int elevel;
|
||||
|
||||
Assert(params != NULL);
|
||||
Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
|
||||
|
||||
/*
|
||||
* Open the relation and get the appropriate lock on it.
|
||||
*
|
||||
* There's a race condition here: the relation may have gone away since
|
||||
* the last time we saw it. If so, we don't need to vacuum or analyze it.
|
||||
*
|
||||
* If we've been asked not to wait for the relation lock, acquire it first
|
||||
* in non-blocking mode, before calling try_relation_open().
|
||||
*/
|
||||
if (!(options & VACOPT_SKIP_LOCKED))
|
||||
onerel = try_relation_open(relid, lmode);
|
||||
else if (ConditionalLockRelationOid(relid, lmode))
|
||||
onerel = try_relation_open(relid, NoLock);
|
||||
else
|
||||
{
|
||||
onerel = NULL;
|
||||
rel_lock = false;
|
||||
}
|
||||
|
||||
/* if relation is opened, leave */
|
||||
if (onerel)
|
||||
return onerel;
|
||||
|
||||
/*
|
||||
* Relation could not be opened, hence generate if possible a log
|
||||
* informing on the situation.
|
||||
*
|
||||
* If the RangeVar is not defined, we do not have enough information to
|
||||
* provide a meaningful log statement. Chances are that the caller has
|
||||
* intentionally not provided this information so that this logging is
|
||||
* skipped, anyway.
|
||||
*/
|
||||
if (relation == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Determine the log level.
|
||||
*
|
||||
* For autovacuum logs, we emit a LOG if log_autovacuum_min_duration is
|
||||
* not disabled. For manual VACUUM or ANALYZE, we emit a WARNING to match
|
||||
* the log statements in the permission checks.
|
||||
*/
|
||||
if (!IsAutoVacuumWorkerProcess())
|
||||
elevel = WARNING;
|
||||
else if (params->log_min_duration >= 0)
|
||||
elevel = LOG;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if ((options & VACOPT_VACUUM) != 0)
|
||||
{
|
||||
if (!rel_lock)
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||
errmsg("skipping vacuum of \"%s\" --- lock not available",
|
||||
relation->relname)));
|
||||
else
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
|
||||
relation->relname)));
|
||||
|
||||
/*
|
||||
* For VACUUM ANALYZE, both logs could show up, but just generate
|
||||
* information for VACUUM as that would be the first one to be
|
||||
* processed.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((options & VACOPT_ANALYZE) != 0)
|
||||
{
|
||||
if (!rel_lock)
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||
errmsg("skipping analyze of \"%s\" --- lock not available",
|
||||
relation->relname)));
|
||||
else
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("skipping analyze of \"%s\" --- relation no longer exists",
|
||||
relation->relname)));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a VacuumRelation, fill in the table OID if it wasn't specified,
|
||||
* and optionally add VacuumRelations for partitions of the table.
|
||||
@ -1400,7 +1506,6 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
|
||||
Oid save_userid;
|
||||
int save_sec_context;
|
||||
int save_nestlevel;
|
||||
bool rel_lock = true;
|
||||
|
||||
Assert(params != NULL);
|
||||
|
||||
@ -1455,68 +1560,12 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
|
||||
*/
|
||||
lmode = (options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock;
|
||||
|
||||
/*
|
||||
* Open the relation and get the appropriate lock on it.
|
||||
*
|
||||
* There's a race condition here: the rel may have gone away since the
|
||||
* last time we saw it. If so, we don't need to vacuum it.
|
||||
*
|
||||
* If we've been asked not to wait for the relation lock, acquire it first
|
||||
* in non-blocking mode, before calling try_relation_open().
|
||||
*/
|
||||
if (!(options & VACOPT_SKIP_LOCKED))
|
||||
onerel = try_relation_open(relid, lmode);
|
||||
else if (ConditionalLockRelationOid(relid, lmode))
|
||||
onerel = try_relation_open(relid, NoLock);
|
||||
else
|
||||
{
|
||||
onerel = NULL;
|
||||
rel_lock = false;
|
||||
}
|
||||
/* open the relation and get the appropriate lock on it */
|
||||
onerel = vacuum_open_relation(relid, relation, params, options, lmode);
|
||||
|
||||
/*
|
||||
* If we failed to open or lock the relation, emit a log message before
|
||||
* exiting.
|
||||
*/
|
||||
/* leave if relation could not be opened or locked */
|
||||
if (!onerel)
|
||||
{
|
||||
int elevel = 0;
|
||||
|
||||
/*
|
||||
* Determine the log level.
|
||||
*
|
||||
* If the RangeVar is not defined, we do not have enough information
|
||||
* to provide a meaningful log statement. Chances are that
|
||||
* vacuum_rel's caller has intentionally not provided this information
|
||||
* so that this logging is skipped, anyway.
|
||||
*
|
||||
* Otherwise, for autovacuum logs, we emit a LOG if
|
||||
* log_autovacuum_min_duration is not disabled. For manual VACUUM, we
|
||||
* emit a WARNING to match the log statements in the permission
|
||||
* checks.
|
||||
*/
|
||||
if (relation != NULL)
|
||||
{
|
||||
if (!IsAutoVacuumWorkerProcess())
|
||||
elevel = WARNING;
|
||||
else if (params->log_min_duration >= 0)
|
||||
elevel = LOG;
|
||||
}
|
||||
|
||||
if (elevel != 0)
|
||||
{
|
||||
if (!rel_lock)
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
|
||||
errmsg("skipping vacuum of \"%s\" --- lock not available",
|
||||
relation->relname)));
|
||||
else
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("skipping vacuum of \"%s\" --- relation no longer exists",
|
||||
relation->relname)));
|
||||
}
|
||||
|
||||
PopActiveSnapshot();
|
||||
CommitTransactionCommand();
|
||||
return false;
|
||||
|
@ -188,6 +188,8 @@ extern void vac_update_datfrozenxid(void);
|
||||
extern void vacuum_delay_point(void);
|
||||
extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple,
|
||||
int options);
|
||||
extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
|
||||
VacuumParams *params, int options, LOCKMODE lmode);
|
||||
|
||||
/* in commands/vacuumlazy.c */
|
||||
extern void lazy_vacuum_rel(Relation onerel, int options,
|
||||
|
Loading…
Reference in New Issue
Block a user