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.
REL7_2_STABLE
Tom Lane 25 years ago
parent 20ca834ce9
commit 4046e58c24
  1. 4
      src/backend/commands/Makefile
  2. 118
      src/backend/commands/vacuum.c
  3. 1026
      src/backend/commands/vacuumlazy.c
  4. 10
      src/include/commands/vacuum.h

@ -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

@ -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

@ -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);

Loading…
Cancel
Save