New-style vacuum neglected to update pg_class statistics about indexes
if there were no deletions to do.
This commit is contained in:
parent
75586cb584
commit
ccf193f1a5
@ -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);
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user