Now that we allow ANALYZE to run inside a transaction block, the locks

it takes could be held for quite awhile after the analyze step completes.
Rethink locking of pg_statistic in light of this fact.  The original
scheme took an exclusive lock on pg_statistic, which was okay when the
lock could be expected to be released shortly, but that doesn't hold
anymore.  Back off to a normal writer's lock (RowExclusiveLock).  This
allows concurrent ANALYZE of nonoverlapping sets of tables, at the price
that concurrent ANALYZEs of the same table may fail with 'tuple
concurrently updated'.
REL7_3_STABLE
Tom Lane 24 years ago
parent 5c3102d6d1
commit 2e10863bf5
  1. 23
      src/backend/commands/analyze.c

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.41 2002/08/05 03:29:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.42 2002/08/11 00:08:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -272,7 +272,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
*/
if (attr_cnt <= 0)
{
relation_close(onerel, NoLock);
relation_close(onerel, AccessShareLock);
return;
}
@ -1644,6 +1644,15 @@ compare_mcvs(const void *a, const void *b)
* This could possibly be made to work, but it's not worth the trouble.
* Note analyze_rel() has seen to it that we won't come here when
* vacuuming pg_statistic itself.
*
* Note: if two backends concurrently try to analyze the same relation,
* the second one is likely to fail here with a "tuple concurrently
* updated" error. This is slightly annoying, but no real harm is done.
* We could prevent the problem by using a stronger lock on the
* relation for ANALYZE (ie, ShareUpdateExclusiveLock instead
* of AccessShareLock); but that cure seems worse than the disease,
* especially now that ANALYZE doesn't start a new transaction
* for each relation. The lock could be held for a long time...
*/
static void
update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
@ -1651,12 +1660,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
Relation sd;
int attno;
/*
* We use an ExclusiveLock on pg_statistic to ensure that only one
* backend is writing it at a time --- without that, we might have to
* deal with concurrent updates here, and it's not worth the trouble.
*/
sd = heap_openr(StatisticRelationName, ExclusiveLock);
sd = heap_openr(StatisticRelationName, RowExclusiveLock);
for (attno = 0; attno < natts; attno++)
{
@ -1789,6 +1793,5 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
heap_freetuple(stup);
}
/* close rel, but hold lock till upcoming commit */
heap_close(sd, NoLock);
heap_close(sd, RowExclusiveLock);
}

Loading…
Cancel
Save