From ccf193f1a595106cacb946a41ef39e1cb2259e60 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 18 Jul 2001 00:46:25 +0000 Subject: [PATCH] New-style vacuum neglected to update pg_class statistics about indexes if there were no deletions to do. --- src/backend/commands/vacuum.c | 69 ++++++++++++++---------- src/backend/commands/vacuumlazy.c | 89 +++++++++++++++++++++++++++++-- src/include/commands/vacuum.h | 3 +- 3 files changed, 128 insertions(+), 33 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index c53fa05812..8e141133a4 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * 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); static void scan_index(Relation indrel, double num_tuples); 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, BlockNumber rel_pages); static VacPage copy_vac_page(VacPage vacpage); 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, size_t nelem, size_t size, 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. + * + * We use this when we have no deletions to do. */ static void scan_index(Relation indrel, double num_tuples) { - RetrieveIndexResult res; - IndexScanDesc iscan; - BlockNumber nipages; - double nitups; + IndexBulkDeleteResult *stats; VacRUsage ru0; vac_init_rusage(&ru0); - /* walk through the entire index */ - iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL); - nitups = 0; + /* + * 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); - while ((res = index_getnext(iscan, ForwardScanDirection)) - != (RetrieveIndexResult) NULL) - { - nitups += 1; - pfree(res); - } - - index_endscan(iscan); + if (!stats) + return; /* now update statistics in pg_class */ - nipages = RelationGetNumberOfBlocks(indrel); - vac_update_relstats(RelationGetRelid(indrel), nipages, nitups, false); + 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), nipages, nitups, + RelationGetRelationName(indrel), + stats->num_pages, stats->num_index_tuples, vac_show_rusage(&ru0)); /* * 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. */ - if (nitups != num_tuples) + if (stats->num_index_tuples != num_tuples) { - if (nitups > num_tuples || - ! is_partial_index(indrel)) + if (stats->num_index_tuples > num_tuples || + ! vac_is_partial_index(indrel)) elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\ \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 || - ! 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).\ \n\tRecreate the index.", RelationGetRelationName(indrel), @@ -2331,6 +2332,15 @@ tid_reaped(ItemPointer itemptr, void *state) 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 * 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; HeapTuple cachetuple; @@ -2570,7 +2583,7 @@ is_partial_index(Relation indrel) ObjectIdGetDatum(RelationGetRelid(indrel)), 0, 0, 0); if (!HeapTupleIsValid(cachetuple)) - elog(ERROR, "is_partial_index: index %u not found", + elog(ERROR, "vac_is_partial_index: index %u not found", RelationGetRelid(indrel)); indexStruct = (Form_pg_index) GETSTRUCT(cachetuple); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index b78f933f0c..f509086b52 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -31,7 +31,7 @@ * * * 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, Relation *Irel, int nindexes); 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 int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, int tupindex, LVRelStats *vacrelstats); @@ -113,6 +114,7 @@ static void lazy_record_dead_tuple(LVRelStats *vacrelstats, static void lazy_record_free_space(LVRelStats *vacrelstats, BlockNumber page, Size avail); 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 int vac_cmp_itemptr(const void *left, const void *right); @@ -197,6 +199,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, tups_vacuumed, nkeep, nunused; + bool did_vacuum_index = false; int i; VacRUsage ru0; @@ -235,6 +238,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, /* Remove index entries */ for (i = 0; i < nindexes; i++) lazy_vacuum_index(Irel[i], vacrelstats); + did_vacuum_index = true; /* Remove tuples from heap */ lazy_vacuum_heap(onerel, vacrelstats); /* Forget the now-vacuumed tuples, and press on */ @@ -378,6 +382,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ReleaseBuffer(buf); } + /* save stats for use later */ + vacrelstats->rel_tuples = num_tuples; + /* If any tuples need to be deleted, perform final vacuum cycle */ /* XXX put a threshold on min nuber of tuples here? */ if (vacrelstats->num_dead_tuples > 0) @@ -388,9 +395,12 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, /* Remove tuples from heap */ lazy_vacuum_heap(onerel, vacrelstats); } - - /* save stats for use later */ - vacrelstats->rel_tuples = num_tuples; + else if (! did_vacuum_index) + { + /* 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; \ 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; } +/* + * 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. * @@ -955,6 +1027,15 @@ lazy_tid_reaped(ItemPointer itemptr, void *state) 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 * free space in the relation, discarding any old info the map may have. diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 9fd6513e91..0d362bb180 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -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.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, double num_tuples, bool hasindex); +extern bool vac_is_partial_index(Relation indrel); extern void vac_init_rusage(VacRUsage *ru0); extern const char *vac_show_rusage(VacRUsage *ru0);