Skip to content

Commit 2e10863

Browse files
committed
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'.
1 parent 5c3102d commit 2e10863

File tree

1 file changed

+13
-10
lines changed

1 file changed

+13
-10
lines changed

src/backend/commands/analyze.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.41 2002/08/05 03:29:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.42 2002/08/11 00:08:48 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -272,7 +272,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
272272
*/
273273
if (attr_cnt <= 0)
274274
{
275-
relation_close(onerel, NoLock);
275+
relation_close(onerel, AccessShareLock);
276276
return;
277277
}
278278

@@ -1644,19 +1644,23 @@ compare_mcvs(const void *a, const void *b)
16441644
* This could possibly be made to work, but it's not worth the trouble.
16451645
* Note analyze_rel() has seen to it that we won't come here when
16461646
* vacuuming pg_statistic itself.
1647+
*
1648+
* Note: if two backends concurrently try to analyze the same relation,
1649+
* the second one is likely to fail here with a "tuple concurrently
1650+
* updated" error. This is slightly annoying, but no real harm is done.
1651+
* We could prevent the problem by using a stronger lock on the
1652+
* relation for ANALYZE (ie, ShareUpdateExclusiveLock instead
1653+
* of AccessShareLock); but that cure seems worse than the disease,
1654+
* especially now that ANALYZE doesn't start a new transaction
1655+
* for each relation. The lock could be held for a long time...
16471656
*/
16481657
static void
16491658
update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
16501659
{
16511660
Relation sd;
16521661
int attno;
16531662

1654-
/*
1655-
* We use an ExclusiveLock on pg_statistic to ensure that only one
1656-
* backend is writing it at a time --- without that, we might have to
1657-
* deal with concurrent updates here, and it's not worth the trouble.
1658-
*/
1659-
sd = heap_openr(StatisticRelationName, ExclusiveLock);
1663+
sd = heap_openr(StatisticRelationName, RowExclusiveLock);
16601664

16611665
for (attno = 0; attno < natts; attno++)
16621666
{
@@ -1789,6 +1793,5 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
17891793
heap_freetuple(stup);
17901794
}
17911795

1792-
/* close rel, but hold lock till upcoming commit */
1793-
heap_close(sd, NoLock);
1796+
heap_close(sd, RowExclusiveLock);
17941797
}

0 commit comments

Comments
 (0)