New-style vacuum neglected to update pg_class statistics about indexes
authorTom Lane
Wed, 18 Jul 2001 00:46:25 +0000 (00:46 +0000)
committerTom Lane
Wed, 18 Jul 2001 00:46:25 +0000 (00:46 +0000)
if there were no deletions to do.

src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/include/commands/vacuum.h

index c53fa05812e1aba3698df949e25b5d5953ab0689..8e141133a427809c043629c54c0d0b5efde32345 100644 (file)
@@ -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;
-
-   while ((res = index_getnext(iscan, ForwardScanDirection))
-          != (RetrieveIndexResult) NULL)
-   {
-       nitups += 1;
-       pfree(res);
-   }
+   /*
+    * 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);
 
-   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);
 
index b78f933f0c3c4ecfd1c2d74b2265ee407c4ad9a3..f509086b52f3c5aea094b4f7c1eadd2847e687d5 100644 (file)
@@ -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.
index 9fd6513e91e6b4a7197a1d40d121119b600c9023..0d362bb1801ef58a960f5968b44c9f71bc304877 100644 (file)
@@ -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);