summaryrefslogtreecommitdiff
path: root/src/backend/commands/vacuum.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/vacuum.c')
-rw-r--r--src/backend/commands/vacuum.c90
1 files changed, 49 insertions, 41 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a7a557fb0fe..0d4984cde6a 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.177 2000/12/08 06:43:44 inoue Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.178 2000/12/22 00:51:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,7 +61,7 @@ static void vacuum_init(void);
static void vacuum_shutdown(void);
static void vac_vacuum(NameData *VacRelP, bool analyze, List *anal_cols2);
static VRelList getrels(NameData *VacRelP);
-static void vacuum_rel(Oid relid, bool is_toastrel);
+static void vacuum_rel(Oid relid);
static void scan_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages, VacPageList fraged_pages);
static void repair_frag(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages, VacPageList fraged_pages, int nindices, Relation *Irel);
static void vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacpagelist);
@@ -239,7 +239,7 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *anal_cols2)
/* vacuum each heap relation */
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
{
- vacuum_rel(cur->vrl_relid, false);
+ vacuum_rel(cur->vrl_relid);
/* analyze separately so locking is minimized */
if (analyze)
analyze_rel(cur->vrl_relid, anal_cols2, MESSAGE_LEVEL);
@@ -308,7 +308,7 @@ getrels(NameData *VacRelP)
if (rkind != RELKIND_RELATION)
{
- elog(NOTICE, "Vacuum: can not process indecies, views and certain system tables");
+ elog(NOTICE, "Vacuum: can not process indices, views and certain system tables");
continue;
}
@@ -342,23 +342,25 @@ getrels(NameData *VacRelP)
* vacuum_rel() -- vacuum one heap relation
*
* This routine vacuums a single heap, cleans out its indices, and
- * updates its statistics num_pages and num_tuples statistics.
+ * updates its num_pages and num_tuples statistics.
*
* Doing one heap at a time incurs extra overhead, since we need to
* check that the heap exists again just before we vacuum it. The
* reason that we do this is so that vacuuming can be spread across
* many small transactions. Otherwise, two-phase locking would require
* us to lock the entire database during one pass of the vacuum cleaner.
+ *
+ * At entry and exit, we are not inside a transaction.
*/
static void
-vacuum_rel(Oid relid, bool is_toastrel)
+vacuum_rel(Oid relid)
{
Relation onerel;
+ LockRelId onerelid;
VacPageListData vacuum_pages; /* List of pages to vacuum and/or clean
- * indices */
+ * indices */
VacPageListData fraged_pages; /* List of pages with space enough for
- * re-using */
- VacPage *vacpage;
+ * re-using */
Relation *Irel;
int32 nindices,
i;
@@ -366,8 +368,8 @@ vacuum_rel(Oid relid, bool is_toastrel)
bool reindex = false;
Oid toast_relid;
- if (!is_toastrel)
- StartTransactionCommand();
+ /* Begin a transaction for vacuuming this relation */
+ StartTransactionCommand();
/*
* Check for user-requested abort. Note we want this to be inside a
@@ -384,8 +386,7 @@ vacuum_rel(Oid relid, bool is_toastrel)
ObjectIdGetDatum(relid),
0, 0, 0))
{
- if (!is_toastrel)
- CommitTransactionCommand();
+ CommitTransactionCommand();
return;
}
@@ -403,13 +404,25 @@ vacuum_rel(Oid relid, bool is_toastrel)
elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it",
RelationGetRelationName(onerel));
heap_close(onerel, AccessExclusiveLock);
- if (!is_toastrel)
- CommitTransactionCommand();
+ CommitTransactionCommand();
return;
}
/*
- * Remember the relation'ss TOAST relation for later
+ * Get a session-level exclusive lock too. This will protect our
+ * exclusive access to the relation across multiple transactions,
+ * so that we can vacuum the relation's TOAST table (if any) secure
+ * in the knowledge that no one is diddling the parent relation.
+ *
+ * NOTE: this cannot block, even if someone else is waiting for access,
+ * because the lock manager knows that both lock requests are from the
+ * same process.
+ */
+ onerelid = onerel->rd_lockInfo.lockRelId;
+ LockRelationForSession(&onerelid, AccessExclusiveLock);
+
+ /*
+ * Remember the relation's TOAST relation for later
*/
toast_relid = onerel->rd_rel->reltoastrelid;
@@ -500,21 +513,6 @@ vacuum_rel(Oid relid, bool is_toastrel)
if (reindex)
activate_indexes_of_a_table(relid, true);
- /*
- * ok - free vacuum_pages list of reaped pages
- *
- * Isn't this a waste of code? Upcoming commit should free memory, no?
- */
- if (vacuum_pages.num_pages > 0)
- {
- vacpage = vacuum_pages.pagedesc;
- for (i = 0; i < vacuum_pages.num_pages; i++, vacpage++)
- pfree(*vacpage);
- pfree(vacuum_pages.pagedesc);
- if (fraged_pages.num_pages > 0)
- pfree(fraged_pages.pagedesc);
- }
-
/* all done with this class, but hold lock until commit */
heap_close(onerel, NoLock);
@@ -524,18 +522,24 @@ vacuum_rel(Oid relid, bool is_toastrel)
vacrelstats);
/*
+ * Complete the transaction and free all temporary memory used.
+ */
+ CommitTransactionCommand();
+
+ /*
* If the relation has a secondary toast one, vacuum that too
- * while we still hold the lock on the master table. We don't
- * need to propagate "analyze" to it, because the toaster
+ * while we still hold the session lock on the master table.
+ * We don't need to propagate "analyze" to it, because the toaster
* always uses hardcoded index access and statistics are
* totally unimportant for toast relations
*/
if (toast_relid != InvalidOid)
- vacuum_rel(toast_relid, true);
+ vacuum_rel(toast_relid);
- /* next command frees attribute stats */
- if (!is_toastrel)
- CommitTransactionCommand();
+ /*
+ * Now release the session-level lock on the master table.
+ */
+ UnlockRelationForSession(&onerelid, AccessExclusiveLock);
}
/*
@@ -1786,9 +1790,13 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
if (num_moved > 0)
{
/*
- * We have to commit our tuple' movings before we'll truncate
- * relation, but we shouldn't lose our locks. And so - quick hack:
- * record status of current transaction as committed, and continue.
+ * We have to commit our tuple movings before we truncate the
+ * relation. Ideally we should do Commit/StartTransactionCommand
+ * here, relying on the session-level table lock to protect our
+ * exclusive access to the relation. However, that would require
+ * a lot of extra code to close and re-open the relation, indices,
+ * etc. For now, a quick hack: record status of current transaction
+ * as committed, and continue.
*/
RecordTransactionCommit();
}
@@ -1852,7 +1860,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
/*
* Reflect the motion of system tuples to catalog cache here.
*/
- CommandCounterIncrement();
+ CommandCounterIncrement();
if (Nvacpagelist.num_pages > 0)
{