aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-09-17 22:50:31 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-09-17 22:50:31 +0000
commitda7540b9d17c09c3b2e49a7580e5f42dcc4a4bcd (patch)
tree9c1d30fc2f7bf47ee4355f52bb604872b9aec803 /src
parent2e5e856f6b4f4e7445ec4b14fc4504469f6f4f54 (diff)
downloadpostgresql-da7540b9d17c09c3b2e49a7580e5f42dcc4a4bcd.tar.gz
postgresql-da7540b9d17c09c3b2e49a7580e5f42dcc4a4bcd.zip
Change ANALYZE to take ShareUpdateExclusiveLock not AccessShareLock on
the table being analyzed. This prevents two ANALYZEs from running concurrently on the same table and possibly suffering concurrent-update failures while trying to store their results into pg_statistic. The downside is that a database-wide ANALYZE executed within a transaction block will hold ShareUpdateExclusiveLock on many tables simultaneously, which could lead to concurrency issues or even deadlock against another such ANALYZE. However, this seems a corner case of less importance than getting unexpected errors from a foreground ANALYZE when autovacuum elects to analyze the same table concurrently. Per discussion.
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/analyze.c38
1 files changed, 19 insertions, 19 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 2930eacb503..f9e41e3531b 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.97 2006/08/18 16:09:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.98 2006/09/17 22:50:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -129,10 +129,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
CHECK_FOR_INTERRUPTS();
/*
- * Open the relation, getting only a read lock on it. If the rel has
- * been dropped since we last saw it, we don't need to process it.
+ * Open the relation, getting ShareUpdateExclusiveLock to ensure that
+ * two ANALYZEs don't run on it concurrently. (This also locks out
+ * a 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.
*/
- onerel = try_relation_open(relid, AccessShareLock);
+ onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
if (!onerel)
return;
@@ -147,7 +151,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
ereport(WARNING,
(errmsg("skipping \"%s\" --- only table or database owner can analyze it",
RelationGetRelationName(onerel))));
- relation_close(onerel, AccessShareLock);
+ relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
@@ -162,7 +166,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
ereport(WARNING,
(errmsg("skipping \"%s\" --- cannot analyze indexes, views, or special system tables",
RelationGetRelationName(onerel))));
- relation_close(onerel, AccessShareLock);
+ relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
@@ -174,7 +178,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
*/
if (isOtherTempNamespace(RelationGetNamespace(onerel)))
{
- relation_close(onerel, AccessShareLock);
+ relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
@@ -183,7 +187,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
*/
if (RelationGetRelid(onerel) == StatisticRelationId)
{
- relation_close(onerel, AccessShareLock);
+ relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
@@ -317,7 +321,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
0, 0);
vac_close_indexes(nindexes, Irel, AccessShareLock);
- relation_close(onerel, AccessShareLock);
+ relation_close(onerel, ShareUpdateExclusiveLock);
return;
}
@@ -444,7 +448,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
/*
* Close source relation now, but keep lock so that no one deletes it
* before we commit. (If someone did, they'd fail to clean up the entries
- * we made in pg_statistic.)
+ * we made in pg_statistic. Also, releasing the lock before commit would
+ * expose us to concurrent-update failures in update_attstats.)
*/
relation_close(onerel, NoLock);
}
@@ -1079,14 +1084,9 @@ compare_rows(const void *a, const void *b)
* 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...
+ * Note: there would be a race condition here if two backends could
+ * ANALYZE the same table concurrently. Presently, we lock that out
+ * by taking a self-exclusive lock on the relation in analyze_rel().
*/
static void
update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
@@ -1202,7 +1202,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
else
{
/* No, insert new tuple */
- stup = heap_formtuple(sd->rd_att, values, nulls);
+ stup = heap_formtuple(RelationGetDescr(sd), values, nulls);
simple_heap_insert(sd, stup);
}