New-style vacuum neglected to update pg_class statistics about indexes

if there were no deletions to do.
This commit is contained in:
Tom Lane 2001-07-18 00:46:25 +00:00
parent 75586cb584
commit ccf193f1a5
3 changed files with 128 additions and 33 deletions

View File

@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.205 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.206 2001/07/18 00:46:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -129,11 +129,11 @@ static void vacuum_index(VacPageList vacpagelist, Relation indrel,
double num_tuples, int keep_tuples); double num_tuples, int keep_tuples);
static void scan_index(Relation indrel, double num_tuples); static void scan_index(Relation indrel, double num_tuples);
static bool tid_reaped(ItemPointer itemptr, void *state); static bool tid_reaped(ItemPointer itemptr, void *state);
static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
static void vac_update_fsm(Relation onerel, VacPageList fraged_pages, 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 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,
int (*compar) (const void *, const void *)); int (*compar) (const void *, const void *));
@ -2178,51 +2178,52 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
/* /*
* scan_index() -- scan one index relation to update statistic. * scan_index() -- scan one index relation to update statistic.
*
* We use this when we have no deletions to do.
*/ */
static void static void
scan_index(Relation indrel, double num_tuples) scan_index(Relation indrel, double num_tuples)
{ {
RetrieveIndexResult res; IndexBulkDeleteResult *stats;
IndexScanDesc iscan;
BlockNumber nipages;
double nitups;
VacRUsage ru0; VacRUsage ru0;
vac_init_rusage(&ru0); vac_init_rusage(&ru0);
/* walk through the entire index */ /*
iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL); * Even though we're not planning to delete anything, use the
nitups = 0; * ambulkdelete call, so that the scan happens within the index AM
* for more speed.
*/
stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
while ((res = index_getnext(iscan, ForwardScanDirection)) if (!stats)
!= (RetrieveIndexResult) NULL) return;
{
nitups += 1;
pfree(res);
}
index_endscan(iscan);
/* now update statistics in pg_class */ /* now update statistics in pg_class */
nipages = RelationGetNumberOfBlocks(indrel); vac_update_relstats(RelationGetRelid(indrel),
vac_update_relstats(RelationGetRelid(indrel), nipages, nitups, false); stats->num_pages, stats->num_index_tuples,
false);
elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %.0f.\n\t%s", elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %.0f.\n\t%s",
RelationGetRelationName(indrel), nipages, nitups, RelationGetRelationName(indrel),
stats->num_pages, stats->num_index_tuples,
vac_show_rusage(&ru0)); vac_show_rusage(&ru0));
/* /*
* Check for tuple count mismatch. If the index is partial, then * Check for tuple count mismatch. If the index is partial, then
* it's OK for it to have fewer tuples than the heap; else we got trouble. * it's OK for it to have fewer tuples than the heap; else we got trouble.
*/ */
if (nitups != num_tuples) if (stats->num_index_tuples != num_tuples)
{ {
if (nitups > num_tuples || if (stats->num_index_tuples > num_tuples ||
! is_partial_index(indrel)) ! vac_is_partial_index(indrel))
elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\ elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
\n\tRecreate the index.", \n\tRecreate the index.",
RelationGetRelationName(indrel), nitups, num_tuples); RelationGetRelationName(indrel),
stats->num_index_tuples, num_tuples);
} }
pfree(stats);
} }
/* /*
@ -2269,7 +2270,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
if (stats->num_index_tuples != num_tuples + keep_tuples) if (stats->num_index_tuples != num_tuples + keep_tuples)
{ {
if (stats->num_index_tuples > num_tuples + keep_tuples || if (stats->num_index_tuples > num_tuples + keep_tuples ||
! is_partial_index(indrel)) ! vac_is_partial_index(indrel))
elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\ elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
\n\tRecreate the index.", \n\tRecreate the index.",
RelationGetRelationName(indrel), RelationGetRelationName(indrel),
@ -2331,6 +2332,15 @@ tid_reaped(ItemPointer itemptr, void *state)
return true; return true;
} }
/*
* Dummy version for scan_index.
*/
static bool
dummy_tid_reaped(ItemPointer itemptr, void *state)
{
return false;
}
/* /*
* Update the shared Free Space Map with the info we now have about * Update the shared Free Space Map with the info we now have about
* free space in the relation, discarding any old info the map may have. * free space in the relation, discarding any old info the map may have.
@ -2552,8 +2562,11 @@ vac_close_indexes(int nindexes, Relation *Irel)
} }
static bool /*
is_partial_index(Relation indrel) * Is an index partial (ie, could it contain fewer tuples than the heap?)
*/
bool
vac_is_partial_index(Relation indrel)
{ {
bool result; bool result;
HeapTuple cachetuple; HeapTuple cachetuple;
@ -2570,7 +2583,7 @@ is_partial_index(Relation indrel)
ObjectIdGetDatum(RelationGetRelid(indrel)), ObjectIdGetDatum(RelationGetRelid(indrel)),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(cachetuple)) if (!HeapTupleIsValid(cachetuple))
elog(ERROR, "is_partial_index: index %u not found", elog(ERROR, "vac_is_partial_index: index %u not found",
RelationGetRelid(indrel)); RelationGetRelid(indrel));
indexStruct = (Form_pg_index) GETSTRUCT(cachetuple); indexStruct = (Form_pg_index) GETSTRUCT(cachetuple);

View File

@ -31,7 +31,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.2 2001/07/15 22:48:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.3 2001/07/18 00:46:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -101,6 +101,7 @@ static TransactionId XmaxRecent;
static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
Relation *Irel, int nindexes); Relation *Irel, int nindexes);
static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats); static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
static void lazy_scan_index(Relation indrel, LVRelStats *vacrelstats);
static void lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats); static void lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats); int tupindex, LVRelStats *vacrelstats);
@ -113,6 +114,7 @@ static void lazy_record_dead_tuple(LVRelStats *vacrelstats,
static void lazy_record_free_space(LVRelStats *vacrelstats, static void lazy_record_free_space(LVRelStats *vacrelstats,
BlockNumber page, Size avail); BlockNumber page, Size avail);
static bool lazy_tid_reaped(ItemPointer itemptr, void *state); static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
static void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats); static void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats);
static int vac_cmp_itemptr(const void *left, const void *right); static int vac_cmp_itemptr(const void *left, const void *right);
@ -197,6 +199,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
tups_vacuumed, tups_vacuumed,
nkeep, nkeep,
nunused; nunused;
bool did_vacuum_index = false;
int i; int i;
VacRUsage ru0; VacRUsage ru0;
@ -235,6 +238,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
/* Remove index entries */ /* Remove index entries */
for (i = 0; i < nindexes; i++) for (i = 0; i < nindexes; i++)
lazy_vacuum_index(Irel[i], vacrelstats); lazy_vacuum_index(Irel[i], vacrelstats);
did_vacuum_index = true;
/* Remove tuples from heap */ /* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats); lazy_vacuum_heap(onerel, vacrelstats);
/* Forget the now-vacuumed tuples, and press on */ /* Forget the now-vacuumed tuples, and press on */
@ -378,6 +382,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
ReleaseBuffer(buf); ReleaseBuffer(buf);
} }
/* save stats for use later */
vacrelstats->rel_tuples = num_tuples;
/* If any tuples need to be deleted, perform final vacuum cycle */ /* If any tuples need to be deleted, perform final vacuum cycle */
/* XXX put a threshold on min nuber of tuples here? */ /* XXX put a threshold on min nuber of tuples here? */
if (vacrelstats->num_dead_tuples > 0) if (vacrelstats->num_dead_tuples > 0)
@ -388,9 +395,12 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
/* Remove tuples from heap */ /* Remove tuples from heap */
lazy_vacuum_heap(onerel, vacrelstats); lazy_vacuum_heap(onerel, vacrelstats);
} }
else if (! did_vacuum_index)
/* save stats for use later */ {
vacrelstats->rel_tuples = num_tuples; /* Scan indexes just to update pg_class statistics about them */
for (i = 0; i < nindexes; i++)
lazy_scan_index(Irel[i], vacrelstats);
}
elog(MESSAGE_LEVEL, "Pages %u: Changed %u, Empty %u; \ elog(MESSAGE_LEVEL, "Pages %u: Changed %u, Empty %u; \
Tup %.0f: Vac %.0f, Keep %.0f, UnUsed %.0f.\n\tTotal %s", Tup %.0f: Vac %.0f, Keep %.0f, UnUsed %.0f.\n\tTotal %s",
@ -495,6 +505,68 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
return tupindex; return tupindex;
} }
/*
* lazy_scan_index() -- scan one index relation to update pg_class statistic.
*
* We use this when we have no deletions to do.
*/
static void
lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
{
IndexBulkDeleteResult *stats;
VacRUsage ru0;
vac_init_rusage(&ru0);
/*
* If the index is not partial, skip the scan, and just assume it
* has the same number of tuples as the heap.
*/
if (! vac_is_partial_index(indrel))
{
vac_update_relstats(RelationGetRelid(indrel),
RelationGetNumberOfBlocks(indrel),
vacrelstats->rel_tuples,
false);
return;
}
/*
* If index is unsafe for concurrent access, must lock it;
* but a shared lock should be sufficient.
*/
if (! indrel->rd_am->amconcurrent)
LockRelation(indrel, AccessShareLock);
/*
* Even though we're not planning to delete anything, use the
* ambulkdelete call, so that the scan happens within the index AM
* for more speed.
*/
stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
/*
* Release lock acquired above.
*/
if (! indrel->rd_am->amconcurrent)
UnlockRelation(indrel, AccessShareLock);
if (!stats)
return;
/* now update statistics in pg_class */
vac_update_relstats(RelationGetRelid(indrel),
stats->num_pages, stats->num_index_tuples,
false);
elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %.0f.\n\t%s",
RelationGetRelationName(indrel),
stats->num_pages, stats->num_index_tuples,
vac_show_rusage(&ru0));
pfree(stats);
}
/* /*
* lazy_vacuum_index() -- vacuum one index relation. * lazy_vacuum_index() -- vacuum one index relation.
* *
@ -955,6 +1027,15 @@ lazy_tid_reaped(ItemPointer itemptr, void *state)
return (res != NULL); return (res != NULL);
} }
/*
* Dummy version for lazy_scan_index.
*/
static bool
dummy_tid_reaped(ItemPointer itemptr, void *state)
{
return false;
}
/* /*
* Update the shared Free Space Map with the info we now have about * Update the shared Free Space Map with the info we now have about
* free space in the relation, discarding any old info the map may have. * free space in the relation, discarding any old info the map may have.

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.38 2001/07/13 22:55:59 tgl Exp $ * $Id: vacuum.h,v 1.39 2001/07/18 00:46:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -44,6 +44,7 @@ extern void vac_update_relstats(Oid relid,
BlockNumber num_pages, BlockNumber num_pages,
double num_tuples, double num_tuples,
bool hasindex); bool hasindex);
extern bool vac_is_partial_index(Relation indrel);
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);