1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-25 21:42:33 +03:00

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 # Makefile for commands
# #
# IDENTIFICATION # 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 include $(top_builddir)/src/Makefile.global
OBJS = async.o creatinh.o command.o comment.o copy.o indexcmds.o define.o \ 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 \ explain.o sequence.o trigger.o user.o proclang.o \
dbcommands.o variable.o dbcommands.o variable.o

View File

@ -1,41 +1,39 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* vacuum.c * 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) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/execnodes.h"
#include "storage/freespace.h" #include "storage/freespace.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
@ -123,7 +121,7 @@ static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages); VacPageList vacuum_pages, VacPageList fraged_pages);
static void repair_frag(VRelStats *vacrelstats, Relation onerel, static void repair_frag(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages, VacPageList vacuum_pages, VacPageList fraged_pages,
int nindices, Relation *Irel); int nindexes, Relation *Irel);
static void vacuum_heap(VRelStats *vacrelstats, Relation onerel, static void vacuum_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacpagelist); VacPageList vacpagelist);
static void vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage); 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); BlockNumber rel_pages);
static VacPage copy_vac_page(VacPage vacpage); static VacPage copy_vac_page(VacPage vacpage);
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew); 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 bool is_partial_index(Relation indrel);
static void *vac_bsearch(const void *key, const void *base, static void *vac_bsearch(const void *key, const void *base,
size_t nelem, size_t size, 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 * 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 * 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) if (vacstmt->full)
full_vacuum_rel(onerel); full_vacuum_rel(onerel);
else 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 */ /* all done with this class, but hold lock until commit */
heap_close(onerel, NoLock); heap_close(onerel, NoLock);
@ -596,7 +590,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
/* /*
* full_vacuum_rel() -- perform FULL VACUUM for one heap relation * 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. * updates its num_pages and num_tuples statistics.
* *
* At entry, we have already established a transaction and opened * At entry, we have already established a transaction and opened
@ -606,11 +600,11 @@ static void
full_vacuum_rel(Relation onerel) full_vacuum_rel(Relation onerel)
{ {
VacPageListData vacuum_pages; /* List of pages to vacuum and/or VacPageListData vacuum_pages; /* List of pages to vacuum and/or
* clean indices */ * clean indexes */
VacPageListData fraged_pages; /* List of pages with space enough VacPageListData fraged_pages; /* List of pages with space enough
* for re-using */ * for re-using */
Relation *Irel; Relation *Irel;
int32 nindices, int nindexes,
i; i;
VRelStats *vacrelstats; VRelStats *vacrelstats;
bool reindex = false; bool reindex = false;
@ -633,15 +627,13 @@ full_vacuum_rel(Relation onerel)
vacuum_pages.num_pages = fraged_pages.num_pages = 0; vacuum_pages.num_pages = fraged_pages.num_pages = 0;
scan_heap(vacrelstats, onerel, &vacuum_pages, &fraged_pages); scan_heap(vacrelstats, onerel, &vacuum_pages, &fraged_pages);
/* Now open all indices of the relation */ /* Now open all indexes of the relation */
nindices = 0; vac_open_indexes(onerel, &nindexes, &Irel);
Irel = (Relation *) NULL;
get_indices(onerel, &nindices, &Irel);
if (!Irel) if (!Irel)
reindex = false; reindex = false;
else if (!RelationGetForm(onerel)->relhasindex) else if (!RelationGetForm(onerel)->relhasindex)
reindex = true; reindex = true;
if (nindices > 0) if (nindexes > 0)
vacrelstats->hasindex = true; vacrelstats->hasindex = true;
#ifdef NOT_USED #ifdef NOT_USED
@ -651,7 +643,7 @@ full_vacuum_rel(Relation onerel)
*/ */
if (reindex) if (reindex)
{ {
close_indices(nindices, Irel); vac_close_indexes(nindexes, Irel);
Irel = (Relation *) NULL; Irel = (Relation *) NULL;
activate_indexes_of_a_table(RelationGetRelid(onerel), false); activate_indexes_of_a_table(RelationGetRelid(onerel), false);
} }
@ -662,14 +654,14 @@ full_vacuum_rel(Relation onerel)
{ {
if (vacuum_pages.num_pages > 0) if (vacuum_pages.num_pages > 0)
{ {
for (i = 0; i < nindices; i++) for (i = 0; i < nindexes; i++)
vacuum_index(&vacuum_pages, Irel[i], vacuum_index(&vacuum_pages, Irel[i],
vacrelstats->rel_tuples, 0); vacrelstats->rel_tuples, 0);
} }
else else
{ {
/* just scan indices to update statistic */ /* just scan indexes to update statistic */
for (i = 0; i < nindices; i++) for (i = 0; i < nindexes; i++)
scan_index(Irel[i], vacrelstats->rel_tuples); scan_index(Irel[i], vacrelstats->rel_tuples);
} }
} }
@ -678,12 +670,12 @@ full_vacuum_rel(Relation onerel)
{ {
/* Try to shrink heap */ /* Try to shrink heap */
repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages, repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages,
nindices, Irel); nindexes, Irel);
close_indices(nindices, Irel); vac_close_indexes(nindexes, Irel);
} }
else else
{ {
close_indices(nindices, Irel); vac_close_indexes(nindexes, Irel);
if (vacuum_pages.num_pages > 0) if (vacuum_pages.num_pages > 0)
{ {
/* Clean pages from vacuum_pages list */ /* Clean pages from vacuum_pages list */
@ -835,7 +827,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
itemid = PageGetItemId(page, offnum); 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. * pointing here after crash.
*/ */
if (!ItemIdIsUsed(itemid)) if (!ItemIdIsUsed(itemid))
@ -944,7 +936,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
} }
/* mark it unused on the temp page */ /* mark it unused on the temp page */
lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]); lpp = PageGetItemId(tempPage, offnum);
lpp->lp_flags &= ~LP_USED; lpp->lp_flags &= ~LP_USED;
vacpage->offsets[vacpage->offsets_free++] = offnum; 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 * repair_frag() -- try to repair relation's fragmentation
* *
* This routine marks dead tuples as unused and tries re-use dead space * This routine marks dead tuples as unused and tries re-use dead space
* by moving tuples (and inserting indices if needed). It constructs * by moving tuples (and inserting indexes if needed). It constructs
* Nvacpagelist list of free-ed pages (moved tuples) and clean indices * Nvacpagelist list of free-ed pages (moved tuples) and clean indexes
* for them after committing (in hack-manner - without losing locks * for them after committing (in hack-manner - without losing locks
* and freeing memory!) current transaction. It truncates relation * and freeing memory!) current transaction. It truncates relation
* if some end-blocks are gone away. * 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 static void
repair_frag(VRelStats *vacrelstats, Relation onerel, repair_frag(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages, VacPageList vacuum_pages, VacPageList fraged_pages,
int nindices, Relation *Irel) int nindexes, Relation *Irel)
{ {
TransactionId myXID; TransactionId myXID;
CommandId myCID; CommandId myCID;
@ -1884,7 +1876,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
* relation. Ideally we should do Commit/StartTransactionCommand * relation. Ideally we should do Commit/StartTransactionCommand
* here, relying on the session-level table lock to protect our * here, relying on the session-level table lock to protect our
* exclusive access to the relation. However, that would require * 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 * etc. For now, a quick hack: record status of current
* transaction as committed, and continue. * transaction as committed, and continue.
*/ */
@ -1985,7 +1977,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
if (Nvacpagelist.num_pages > 0) if (Nvacpagelist.num_pages > 0)
{ {
/* vacuum indices again if needed */ /* vacuum indexes again if needed */
if (Irel != (Relation *) NULL) if (Irel != (Relation *) NULL)
{ {
VacPage *vpleft, VacPage *vpleft,
@ -2002,7 +1994,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
*vpright = vpsave; *vpright = vpsave;
} }
Assert(keep_tuples >= 0); Assert(keep_tuples >= 0);
for (i = 0; i < nindices; i++) for (i = 0; i < nindexes; i++)
vacuum_index(&Nvacpagelist, Irel[i], vacuum_index(&Nvacpagelist, Irel[i],
vacrelstats->rel_tuples, keep_tuples); vacrelstats->rel_tuples, keep_tuples);
} }
@ -2175,7 +2167,7 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
START_CRIT_SECTION(); START_CRIT_SECTION();
for (i = 0; i < vacpage->offsets_free; i++) 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; itemid->lp_flags &= ~LP_USED;
} }
uncnt = PageRepairFragmentation(page, unused); 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. * Vpl is the VacPageList of the heap we're currently vacuuming.
* It's locked. Indrel is an index relation on the vacuumed heap. * 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 don't bother to set locks on the index relation here, since
* We let them handle it. * the parent table is exclusive-locked already.
* *
* Finally, we arrange to update the index relation's statistics in * Finally, we arrange to update the index relation's statistics in
* pg_class. * pg_class.
@ -2555,8 +2547,8 @@ vac_cmp_vtlinks(const void *left, const void *right)
} }
static void void
get_indices(Relation relation, int *nindices, Relation **Irel) vac_open_indexes(Relation relation, int *nindexes, Relation **Irel)
{ {
List *indexoidlist, List *indexoidlist,
*indexoidscan; *indexoidscan;
@ -2564,10 +2556,10 @@ get_indices(Relation relation, int *nindices, Relation **Irel)
indexoidlist = RelationGetIndexList(relation); indexoidlist = RelationGetIndexList(relation);
*nindices = length(indexoidlist); *nindexes = length(indexoidlist);
if (*nindices > 0) if (*nindexes > 0)
*Irel = (Relation *) palloc(*nindices * sizeof(Relation)); *Irel = (Relation *) palloc(*nindexes * sizeof(Relation));
else else
*Irel = NULL; *Irel = NULL;
@ -2584,14 +2576,14 @@ get_indices(Relation relation, int *nindices, Relation **Irel)
} }
static void void
close_indices(int nindices, Relation *Irel) vac_close_indexes(int nindexes, Relation *Irel)
{ {
if (Irel == (Relation *) NULL) if (Irel == (Relation *) NULL)
return; return;
while (nindices--) while (nindexes--)
index_close(Irel[nindices]); index_close(Irel[nindexes]);
pfree(Irel); pfree(Irel);
} }
@ -2621,22 +2613,20 @@ is_partial_index(Relation indrel)
static bool static bool
enough_space(VacPage vacpage, Size len) enough_space(VacPage vacpage, Size len)
{ {
len = MAXALIGN(len); len = MAXALIGN(len);
if (len > vacpage->free) if (len > vacpage->free)
return false; return false;
if (vacpage->offsets_used < vacpage->offsets_free) /* there are free /* if there are free itemid(s) and len <= free_space... */
* itemid(s) */ if (vacpage->offsets_used < vacpage->offsets_free)
return true; /* and len <= free_space */ return true;
/* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */ /* noff_used >= noff_free and so we'll have to allocate new itemid */
if (len + MAXALIGN(sizeof(ItemIdData)) <= vacpage->free) if (len + sizeof(ItemIdData) <= vacpage->free)
return true; return true;
return false; 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) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 #endif
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "storage/block.h" #include "utils/rel.h"
/* State structure for vac_init_rusage/vac_show_rusage */ /* State structure for vac_init_rusage/vac_show_rusage */
@ -37,6 +37,9 @@ typedef struct VacRUsage
/* in commands/vacuum.c */ /* in commands/vacuum.c */
extern void vacuum(VacuumStmt *vacstmt); 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, extern void vac_update_relstats(Oid relid,
BlockNumber num_pages, BlockNumber num_pages,
double num_tuples, double num_tuples,
@ -44,6 +47,9 @@ extern void vac_update_relstats(Oid relid,
extern void vac_init_rusage(VacRUsage *ru0); extern void vac_init_rusage(VacRUsage *ru0);
extern const char *vac_show_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 */ /* in commands/analyze.c */
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt); extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);