Initial implementation of concurrent VACUUM. Ifdef'd out for the moment,

because index locking issues are not handled correctly yet.  Need to go
work on the index AMs next.
This commit is contained in:
Tom Lane 2001-07-13 22:55:59 +00:00
parent 20ca834ce9
commit 4046e58c24
4 changed files with 1090 additions and 68 deletions

View File

@ -4,7 +4,7 @@
# Makefile for commands
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.26 2000/08/31 16:09:53 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.27 2001/07/13 22:55:59 tgl Exp $
#
#-------------------------------------------------------------------------
@ -13,7 +13,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = async.o creatinh.o command.o comment.o copy.o indexcmds.o define.o \
remove.o rename.o vacuum.o analyze.o view.o cluster.o \
remove.o rename.o vacuum.o vacuumlazy.o analyze.o view.o cluster.o \
explain.o sequence.o trigger.o user.o proclang.o \
dbcommands.o variable.o

View File

@ -1,41 +1,39 @@
/*-------------------------------------------------------------------------
*
* vacuum.c
* the postgres vacuum cleaner
* The postgres vacuum cleaner.
*
* This file includes the "full" version of VACUUM, as well as control code
* used by all three of full VACUUM, lazy VACUUM, and ANALYZE. See
* vacuumlazy.c and analyze.c for the rest of the code for the latter two.
*
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.203 2001/07/12 04:11:13 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.204 2001/07/13 22:55:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "access/genam.h"
#include "access/heapam.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/pg_index.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "storage/freespace.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@ -123,7 +121,7 @@ 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);
int nindexes, Relation *Irel);
static void vacuum_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacpagelist);
static void vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage);
@ -135,8 +133,6 @@ static void vac_update_fsm(Relation onerel, VacPageList fraged_pages,
BlockNumber rel_pages);
static VacPage copy_vac_page(VacPage vacpage);
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
static void get_indices(Relation relation, int *nindices, Relation **Irel);
static void close_indices(int nindices, Relation *Irel);
static bool is_partial_index(Relation indrel);
static void *vac_bsearch(const void *key, const void *base,
size_t nelem, size_t size,
@ -455,14 +451,6 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
*/
/* XXX Temporary placeholder */
static void
lazy_vacuum_rel(Relation onerel)
{
full_vacuum_rel(onerel);
}
/*
* vacuum_rel() -- vacuum one heap relation
*
@ -554,11 +542,17 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
/*
* Do the actual work --- either FULL or "lazy" vacuum
*
* XXX for the moment, lazy vac not supported unless CONCURRENT_VACUUM
*/
#ifdef CONCURRENT_VACUUM
if (vacstmt->full)
full_vacuum_rel(onerel);
else
lazy_vacuum_rel(onerel);
lazy_vacuum_rel(onerel, vacstmt);
#else
full_vacuum_rel(onerel);
#endif
/* all done with this class, but hold lock until commit */
heap_close(onerel, NoLock);
@ -596,7 +590,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
/*
* full_vacuum_rel() -- perform FULL VACUUM for one heap relation
*
* This routine vacuums a single heap, cleans out its indices, and
* This routine vacuums a single heap, cleans out its indexes, and
* updates its num_pages and num_tuples statistics.
*
* At entry, we have already established a transaction and opened
@ -606,11 +600,11 @@ static void
full_vacuum_rel(Relation onerel)
{
VacPageListData vacuum_pages; /* List of pages to vacuum and/or
* clean indices */
* clean indexes */
VacPageListData fraged_pages; /* List of pages with space enough
* for re-using */
Relation *Irel;
int32 nindices,
int nindexes,
i;
VRelStats *vacrelstats;
bool reindex = false;
@ -633,15 +627,13 @@ full_vacuum_rel(Relation onerel)
vacuum_pages.num_pages = fraged_pages.num_pages = 0;
scan_heap(vacrelstats, onerel, &vacuum_pages, &fraged_pages);
/* Now open all indices of the relation */
nindices = 0;
Irel = (Relation *) NULL;
get_indices(onerel, &nindices, &Irel);
/* Now open all indexes of the relation */
vac_open_indexes(onerel, &nindexes, &Irel);
if (!Irel)
reindex = false;
else if (!RelationGetForm(onerel)->relhasindex)
reindex = true;
if (nindices > 0)
if (nindexes > 0)
vacrelstats->hasindex = true;
#ifdef NOT_USED
@ -651,7 +643,7 @@ full_vacuum_rel(Relation onerel)
*/
if (reindex)
{
close_indices(nindices, Irel);
vac_close_indexes(nindexes, Irel);
Irel = (Relation *) NULL;
activate_indexes_of_a_table(RelationGetRelid(onerel), false);
}
@ -662,14 +654,14 @@ full_vacuum_rel(Relation onerel)
{
if (vacuum_pages.num_pages > 0)
{
for (i = 0; i < nindices; i++)
for (i = 0; i < nindexes; i++)
vacuum_index(&vacuum_pages, Irel[i],
vacrelstats->rel_tuples, 0);
}
else
{
/* just scan indices to update statistic */
for (i = 0; i < nindices; i++)
/* just scan indexes to update statistic */
for (i = 0; i < nindexes; i++)
scan_index(Irel[i], vacrelstats->rel_tuples);
}
}
@ -678,12 +670,12 @@ full_vacuum_rel(Relation onerel)
{
/* Try to shrink heap */
repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages,
nindices, Irel);
close_indices(nindices, Irel);
nindexes, Irel);
vac_close_indexes(nindexes, Irel);
}
else
{
close_indices(nindices, Irel);
vac_close_indexes(nindexes, Irel);
if (vacuum_pages.num_pages > 0)
{
/* Clean pages from vacuum_pages list */
@ -835,7 +827,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
itemid = PageGetItemId(page, offnum);
/*
* Collect un-used items too - it's possible to have indices
* Collect un-used items too - it's possible to have indexes
* pointing here after crash.
*/
if (!ItemIdIsUsed(itemid))
@ -944,7 +936,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
}
/* mark it unused on the temp page */
lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]);
lpp = PageGetItemId(tempPage, offnum);
lpp->lp_flags &= ~LP_USED;
vacpage->offsets[vacpage->offsets_free++] = offnum;
@ -1073,8 +1065,8 @@ Re-using: Free/Avail. Space %.0f/%.0f; EndEmpty/Avail. Pages %u/%u. %s",
* repair_frag() -- try to repair relation's fragmentation
*
* This routine marks dead tuples as unused and tries re-use dead space
* by moving tuples (and inserting indices if needed). It constructs
* Nvacpagelist list of free-ed pages (moved tuples) and clean indices
* by moving tuples (and inserting indexes if needed). It constructs
* Nvacpagelist list of free-ed pages (moved tuples) and clean indexes
* for them after committing (in hack-manner - without losing locks
* and freeing memory!) current transaction. It truncates relation
* if some end-blocks are gone away.
@ -1082,7 +1074,7 @@ Re-using: Free/Avail. Space %.0f/%.0f; EndEmpty/Avail. Pages %u/%u. %s",
static void
repair_frag(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages,
int nindices, Relation *Irel)
int nindexes, Relation *Irel)
{
TransactionId myXID;
CommandId myCID;
@ -1884,7 +1876,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
* 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,
* a lot of extra code to close and re-open the relation, indexes,
* etc. For now, a quick hack: record status of current
* transaction as committed, and continue.
*/
@ -1985,7 +1977,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
if (Nvacpagelist.num_pages > 0)
{
/* vacuum indices again if needed */
/* vacuum indexes again if needed */
if (Irel != (Relation *) NULL)
{
VacPage *vpleft,
@ -2002,7 +1994,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
*vpright = vpsave;
}
Assert(keep_tuples >= 0);
for (i = 0; i < nindices; i++)
for (i = 0; i < nindexes; i++)
vacuum_index(&Nvacpagelist, Irel[i],
vacrelstats->rel_tuples, keep_tuples);
}
@ -2175,7 +2167,7 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
START_CRIT_SECTION();
for (i = 0; i < vacpage->offsets_free; i++)
{
itemid = &(((PageHeader) page)->pd_linp[vacpage->offsets[i] - 1]);
itemid = PageGetItemId(page, vacpage->offsets[i]);
itemid->lp_flags &= ~LP_USED;
}
uncnt = PageRepairFragmentation(page, unused);
@ -2244,9 +2236,9 @@ scan_index(Relation indrel, double num_tuples)
*
* Vpl is the VacPageList of the heap we're currently vacuuming.
* It's locked. Indrel is an index relation on the vacuumed heap.
* We don't set locks on the index relation here, since the indexed
* access methods support locking at different granularities.
* We let them handle it.
*
* We don't bother to set locks on the index relation here, since
* the parent table is exclusive-locked already.
*
* Finally, we arrange to update the index relation's statistics in
* pg_class.
@ -2555,8 +2547,8 @@ vac_cmp_vtlinks(const void *left, const void *right)
}
static void
get_indices(Relation relation, int *nindices, Relation **Irel)
void
vac_open_indexes(Relation relation, int *nindexes, Relation **Irel)
{
List *indexoidlist,
*indexoidscan;
@ -2564,10 +2556,10 @@ get_indices(Relation relation, int *nindices, Relation **Irel)
indexoidlist = RelationGetIndexList(relation);
*nindices = length(indexoidlist);
*nindexes = length(indexoidlist);
if (*nindices > 0)
*Irel = (Relation *) palloc(*nindices * sizeof(Relation));
if (*nindexes > 0)
*Irel = (Relation *) palloc(*nindexes * sizeof(Relation));
else
*Irel = NULL;
@ -2584,14 +2576,14 @@ get_indices(Relation relation, int *nindices, Relation **Irel)
}
static void
close_indices(int nindices, Relation *Irel)
void
vac_close_indexes(int nindexes, Relation *Irel)
{
if (Irel == (Relation *) NULL)
return;
while (nindices--)
index_close(Irel[nindices]);
while (nindexes--)
index_close(Irel[nindexes]);
pfree(Irel);
}
@ -2621,22 +2613,20 @@ is_partial_index(Relation indrel)
static bool
enough_space(VacPage vacpage, Size len)
{
len = MAXALIGN(len);
if (len > vacpage->free)
return false;
if (vacpage->offsets_used < vacpage->offsets_free) /* there are free
* itemid(s) */
return true; /* and len <= free_space */
/* if there are free itemid(s) and len <= free_space... */
if (vacpage->offsets_used < vacpage->offsets_free)
return true;
/* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
if (len + MAXALIGN(sizeof(ItemIdData)) <= vacpage->free)
/* noff_used >= noff_free and so we'll have to allocate new itemid */
if (len + sizeof(ItemIdData) <= vacpage->free)
return true;
return false;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: vacuum.h,v 1.37 2001/07/12 04:11:13 tgl Exp $
* $Id: vacuum.h,v 1.38 2001/07/13 22:55:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -24,7 +24,7 @@
#endif
#include "nodes/parsenodes.h"
#include "storage/block.h"
#include "utils/rel.h"
/* State structure for vac_init_rusage/vac_show_rusage */
@ -37,6 +37,9 @@ typedef struct VacRUsage
/* in commands/vacuum.c */
extern void vacuum(VacuumStmt *vacstmt);
extern void vac_open_indexes(Relation relation, int *nindexes,
Relation **Irel);
extern void vac_close_indexes(int nindexes, Relation *Irel);
extern void vac_update_relstats(Oid relid,
BlockNumber num_pages,
double num_tuples,
@ -44,6 +47,9 @@ extern void vac_update_relstats(Oid relid,
extern void vac_init_rusage(VacRUsage *ru0);
extern const char *vac_show_rusage(VacRUsage *ru0);
/* in commands/vacuumlazy.c */
extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
/* in commands/analyze.c */
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);