Move index vacuum routines to vacuum.c.
authorAmit Kapila <akapila@postgresql.org>
Wed, 22 Dec 2021 02:25:14 +0000 (07:55 +0530)
committerAmit Kapila <akapila@postgresql.org>
Wed, 22 Dec 2021 02:25:14 +0000 (07:55 +0530)
An upcoming patch moves parallel vacuum code out of vacuumlazy.c. This
code restructuring will allow both lazy vacuum and parallel vacuum to use
index vacuum functions.

Author: Masahiko Sawada
Reviewed-by: Hou Zhijie, Amit Kapila
Discussion: https://www.postgresql.org/message-id/20211030212101.ae3qcouatwmy7tbr%40alap3.anarazel.de

src/backend/access/heap/vacuumlazy.c
src/backend/commands/vacuum.c
src/include/commands/vacuum.h
src/tools/pgindent/typedefs.list

index db6becfed549b597bdc58b07d2b87bc78e21e6c0..d8f1217504079a415d29785ab94927c50c9f57ce 100644 (file)
@@ -149,26 +149,6 @@ typedef enum
        VACUUM_ERRCB_PHASE_TRUNCATE
 } VacErrPhase;
 
-/*
- * LVDeadItems stores TIDs whose index tuples are deleted by index vacuuming.
- * Each TID points to an LP_DEAD line pointer from a heap page that has been
- * processed by lazy_scan_prune.
- *
- * Also needed by lazy_vacuum_heap_rel, which marks the same LP_DEAD line
- * pointers as LP_UNUSED during second heap pass.
- */
-typedef struct LVDeadItems
-{
-       int                     max_items;              /* # slots allocated in array */
-       int                     num_items;              /* current # of entries */
-
-       /* Sorted array of TIDs to delete from indexes */
-       ItemPointerData items[FLEXIBLE_ARRAY_MEMBER];
-} LVDeadItems;
-
-#define MAXDEADITEMS(avail_mem) \
-       (((avail_mem) - offsetof(LVDeadItems, items)) / sizeof(ItemPointerData))
-
 /*
  * Shared information among parallel workers.  So this is allocated in the DSM
  * segment.
@@ -339,9 +319,15 @@ typedef struct LVRelState
        VacErrPhase phase;
 
        /*
-        * State managed by lazy_scan_heap() follows
+        * State managed by lazy_scan_heap() follows.
+        *
+        * dead_items stores TIDs whose index tuples are deleted by index
+        * vacuuming. Each TID points to an LP_DEAD line pointer from a heap page
+        * that has been processed by lazy_scan_prune.  Also needed by
+        * lazy_vacuum_heap_rel, which marks the same LP_DEAD line pointers as
+        * LP_UNUSED during second heap pass.
         */
-       LVDeadItems *dead_items;        /* TIDs whose index tuples we'll delete */
+       VacDeadItems *dead_items;       /* TIDs whose index tuples we'll delete */
        BlockNumber rel_pages;          /* total number of pages */
        BlockNumber scanned_pages;      /* number of pages we examined */
        BlockNumber pinskipped_pages;   /* # of pages skipped due to a pin */
@@ -434,11 +420,8 @@ static void lazy_truncate_heap(LVRelState *vacrel);
 static BlockNumber count_nondeletable_pages(LVRelState *vacrel,
                                                                                        bool *lock_waiter_detected);
 static int dead_items_max_items(LVRelState *vacrel);
-static inline Size max_items_to_alloc_size(int max_items);
 static void dead_items_alloc(LVRelState *vacrel, int nworkers);
 static void dead_items_cleanup(LVRelState *vacrel);
-static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
-static int     vac_cmp_itemptr(const void *left, const void *right);
 static bool heap_page_is_all_visible(LVRelState *vacrel, Buffer buf,
                                                                         TransactionId *visibility_cutoff_xid, bool *all_frozen);
 static int     parallel_vacuum_compute_workers(LVRelState *vacrel, int nrequested,
@@ -905,7 +888,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
 static void
 lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
 {
-       LVDeadItems *dead_items;
+       VacDeadItems *dead_items;
        BlockNumber nblocks,
                                blkno,
                                next_unskippable_block,
@@ -2040,7 +2023,7 @@ retry:
         */
        if (lpdead_items > 0)
        {
-               LVDeadItems *dead_items = vacrel->dead_items;
+               VacDeadItems *dead_items = vacrel->dead_items;
                ItemPointerData tmp;
 
                Assert(!prunestate->all_visible);
@@ -2404,7 +2387,7 @@ static int
 lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, Buffer buffer,
                                          int index, Buffer *vmbuffer)
 {
-       LVDeadItems *dead_items = vacrel->dead_items;
+       VacDeadItems *dead_items = vacrel->dead_items;
        Page            page = BufferGetPage(buffer);
        OffsetNumber unused[MaxHeapTuplesPerPage];
        int                     uncnt = 0;
@@ -3019,11 +3002,8 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
                                          double reltuples, LVRelState *vacrel)
 {
        IndexVacuumInfo ivinfo;
-       PGRUsage        ru0;
        LVSavedErrInfo saved_err_info;
 
-       pg_rusage_init(&ru0);
-
        ivinfo.index = indrel;
        ivinfo.analyze_only = false;
        ivinfo.report_progress = false;
@@ -3045,13 +3025,7 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
                                                         InvalidBlockNumber, InvalidOffsetNumber);
 
        /* Do bulk deletion */
-       istat = index_bulk_delete(&ivinfo, istat, lazy_tid_reaped,
-                                                         (void *) vacrel->dead_items);
-
-       ereport(elevel,
-                       (errmsg("scanned index \"%s\" to remove %d row versions",
-                                       vacrel->indname, vacrel->dead_items->num_items),
-                        errdetail_internal("%s", pg_rusage_show(&ru0))));
+       istat = vac_bulkdel_one_index(&ivinfo, istat, (void *) vacrel->dead_items);
 
        /* Revert to the previous phase information for error traceback */
        restore_vacuum_error_info(vacrel, &saved_err_info);
@@ -3076,11 +3050,8 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
                                           LVRelState *vacrel)
 {
        IndexVacuumInfo ivinfo;
-       PGRUsage        ru0;
        LVSavedErrInfo saved_err_info;
 
-       pg_rusage_init(&ru0);
-
        ivinfo.index = indrel;
        ivinfo.analyze_only = false;
        ivinfo.report_progress = false;
@@ -3102,24 +3073,7 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
                                                         VACUUM_ERRCB_PHASE_INDEX_CLEANUP,
                                                         InvalidBlockNumber, InvalidOffsetNumber);
 
-       istat = index_vacuum_cleanup(&ivinfo, istat);
-
-       if (istat)
-       {
-               ereport(elevel,
-                               (errmsg("index \"%s\" now contains %.0f row versions in %u pages",
-                                               RelationGetRelationName(indrel),
-                                               istat->num_index_tuples,
-                                               istat->num_pages),
-                                errdetail("%.0f index row versions were removed.\n"
-                                                  "%u index pages were newly deleted.\n"
-                                                  "%u index pages are currently deleted, of which %u are currently reusable.\n"
-                                                  "%s.",
-                                                  istat->tuples_removed,
-                                                  istat->pages_newly_deleted,
-                                                  istat->pages_deleted, istat->pages_free,
-                                                  pg_rusage_show(&ru0))));
-       }
+       istat = vac_cleanup_one_index(&ivinfo, istat);
 
        /* Revert to the previous phase information for error traceback */
        restore_vacuum_error_info(vacrel, &saved_err_info);
@@ -3481,19 +3435,6 @@ dead_items_max_items(LVRelState *vacrel)
        return (int) max_items;
 }
 
-/*
- * Returns the total required space for VACUUM's dead_items array given a
- * max_items value returned by dead_items_max_items
- */
-static inline Size
-max_items_to_alloc_size(int max_items)
-{
-       Assert(max_items >= MaxHeapTuplesPerPage);
-       Assert(max_items <= MAXDEADITEMS(MaxAllocSize));
-
-       return offsetof(LVDeadItems, items) + sizeof(ItemPointerData) * max_items;
-}
-
 /*
  * Allocate dead_items (either using palloc, or in dynamic shared memory).
  * Sets dead_items in vacrel for caller.
@@ -3504,7 +3445,7 @@ max_items_to_alloc_size(int max_items)
 static void
 dead_items_alloc(LVRelState *vacrel, int nworkers)
 {
-       LVDeadItems *dead_items;
+       VacDeadItems *dead_items;
        int                     max_items;
 
        /*
@@ -3539,7 +3480,7 @@ dead_items_alloc(LVRelState *vacrel, int nworkers)
 
        /* Serial VACUUM case */
        max_items = dead_items_max_items(vacrel);
-       dead_items = (LVDeadItems *) palloc(max_items_to_alloc_size(max_items));
+       dead_items = (VacDeadItems *) palloc(vac_max_items_to_alloc_size(max_items));
        dead_items->max_items = max_items;
        dead_items->num_items = 0;
 
@@ -3565,74 +3506,6 @@ dead_items_cleanup(LVRelState *vacrel)
        parallel_vacuum_end(vacrel);
 }
 
-/*
- *     lazy_tid_reaped() -- is a particular tid deletable?
- *
- *             This has the right signature to be an IndexBulkDeleteCallback.
- *
- *             Assumes dead_items array is sorted (in ascending TID order).
- */
-static bool
-lazy_tid_reaped(ItemPointer itemptr, void *state)
-{
-       LVDeadItems *dead_items = (LVDeadItems *) state;
-       int64           litem,
-                               ritem,
-                               item;
-       ItemPointer res;
-
-       litem = itemptr_encode(&dead_items->items[0]);
-       ritem = itemptr_encode(&dead_items->items[dead_items->num_items - 1]);
-       item = itemptr_encode(itemptr);
-
-       /*
-        * Doing a simple bound check before bsearch() is useful to avoid the
-        * extra cost of bsearch(), especially if dead items on the heap are
-        * concentrated in a certain range.  Since this function is called for
-        * every index tuple, it pays to be really fast.
-        */
-       if (item < litem || item > ritem)
-               return false;
-
-       res = (ItemPointer) bsearch((void *) itemptr,
-                                                               (void *) dead_items->items,
-                                                               dead_items->num_items,
-                                                               sizeof(ItemPointerData),
-                                                               vac_cmp_itemptr);
-
-       return (res != NULL);
-}
-
-/*
- * Comparator routines for use with qsort() and bsearch().
- */
-static int
-vac_cmp_itemptr(const void *left, const void *right)
-{
-       BlockNumber lblk,
-                               rblk;
-       OffsetNumber loff,
-                               roff;
-
-       lblk = ItemPointerGetBlockNumber((ItemPointer) left);
-       rblk = ItemPointerGetBlockNumber((ItemPointer) right);
-
-       if (lblk < rblk)
-               return -1;
-       if (lblk > rblk)
-               return 1;
-
-       loff = ItemPointerGetOffsetNumber((ItemPointer) left);
-       roff = ItemPointerGetOffsetNumber((ItemPointer) right);
-
-       if (loff < roff)
-               return -1;
-       if (loff > roff)
-               return 1;
-
-       return 0;
-}
-
 /*
  * Check if every tuple in the given page is visible to all current and future
  * transactions. Also return the visibility_cutoff_xid which is the highest
@@ -3873,7 +3746,7 @@ parallel_vacuum_begin(LVRelState *vacrel, int nrequested)
        int                     nindexes = vacrel->nindexes;
        ParallelContext *pcxt;
        LVShared   *shared;
-       LVDeadItems *dead_items;
+       VacDeadItems *dead_items;
        LVParallelIndStats *pindstats;
        BufferUsage *buffer_usage;
        WalUsage   *wal_usage;
@@ -3927,7 +3800,7 @@ parallel_vacuum_begin(LVRelState *vacrel, int nrequested)
 
        /* Estimate size for dead_items -- PARALLEL_VACUUM_KEY_DEAD_ITEMS */
        max_items = dead_items_max_items(vacrel);
-       est_dead_items_len = max_items_to_alloc_size(max_items);
+       est_dead_items_len = vac_max_items_to_alloc_size(max_items);
        shm_toc_estimate_chunk(&pcxt->estimator, est_dead_items_len);
        shm_toc_estimate_keys(&pcxt->estimator, 1);
 
@@ -4011,8 +3884,8 @@ parallel_vacuum_begin(LVRelState *vacrel, int nrequested)
        lps->lvshared = shared;
 
        /* Prepare the dead_items space */
-       dead_items = (LVDeadItems *) shm_toc_allocate(pcxt->toc,
-                                                                                                 est_dead_items_len);
+       dead_items = (VacDeadItems *) shm_toc_allocate(pcxt->toc,
+                                                                                                  est_dead_items_len);
        dead_items->max_items = max_items;
        dead_items->num_items = 0;
        MemSet(dead_items->items, 0, sizeof(ItemPointerData) * max_items);
@@ -4138,7 +4011,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
        Relation   *indrels;
        LVParallelIndStats *lvpindstats;
        LVShared   *lvshared;
-       LVDeadItems *dead_items;
+       VacDeadItems *dead_items;
        BufferUsage *buffer_usage;
        WalUsage   *wal_usage;
        int                     nindexes;
@@ -4183,9 +4056,9 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
                                                                                                                false);
 
        /* Set dead_items space (set as worker's vacrel dead_items below) */
-       dead_items = (LVDeadItems *) shm_toc_lookup(toc,
-                                                                                               PARALLEL_VACUUM_KEY_DEAD_ITEMS,
-                                                                                               false);
+       dead_items = (VacDeadItems *) shm_toc_lookup(toc,
+                                                                                                PARALLEL_VACUUM_KEY_DEAD_ITEMS,
+                                                                                                false);
 
        /* Set cost-based vacuum delay */
        VacuumCostActive = (VacuumCostDelay > 0);
index 5c4bc15b441b36da99b0703500a3268086b40d9e..3b481bcf8601c7e2fca9556b84e0e87bece18d63 100644 (file)
@@ -3,10 +3,12 @@
  * vacuum.c
  *       The postgres vacuum cleaner.
  *
- * This file now includes only control and dispatch code for VACUUM and
- * ANALYZE commands.  Regular VACUUM is implemented in vacuumlazy.c,
- * ANALYZE in analyze.c, and VACUUM FULL is a variant of CLUSTER, handled
- * in cluster.c.
+ * This file includes (a) control and dispatch code for VACUUM and ANALYZE
+ * commands, (b) code to compute various vacuum thresholds, and (c) index
+ * vacuum code.
+ *
+ * VACUUM for heap AM is implemented in vacuumlazy.c, ANALYZE in analyze.c, and
+ * VACUUM FULL is a variant of CLUSTER, handled in cluster.c.
  *
  *
  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
@@ -32,6 +34,7 @@
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/namespace.h"
+#include "catalog/index.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_namespace.h"
@@ -51,6 +54,7 @@
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
+#include "utils/pg_rusage.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 
@@ -89,6 +93,8 @@ static void vac_truncate_clog(TransactionId frozenXID,
 static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params);
 static double compute_parallel_delay(void);
 static VacOptValue get_vacoptval_from_boolean(DefElem *def);
+static bool vac_tid_reaped(ItemPointer itemptr, void *state);
+static int     vac_cmp_itemptr(const void *left, const void *right);
 
 /*
  * Primary entry point for manual VACUUM and ANALYZE commands
@@ -2258,3 +2264,143 @@ get_vacoptval_from_boolean(DefElem *def)
 {
        return defGetBoolean(def) ? VACOPTVALUE_ENABLED : VACOPTVALUE_DISABLED;
 }
+
+/*
+ *     vac_bulkdel_one_index() -- bulk-deletion for index relation.
+ *
+ * Returns bulk delete stats derived from input stats
+ */
+IndexBulkDeleteResult *
+vac_bulkdel_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat,
+                                         VacDeadItems *dead_items)
+{
+       PGRUsage        ru0;
+
+       pg_rusage_init(&ru0);
+
+       /* Do bulk deletion */
+       istat = index_bulk_delete(ivinfo, istat, vac_tid_reaped,
+                                                         (void *) dead_items);
+
+       ereport(ivinfo->message_level,
+                       (errmsg("scanned index \"%s\" to remove %d row versions",
+                                       RelationGetRelationName(ivinfo->index),
+                                       dead_items->num_items),
+                        errdetail_internal("%s", pg_rusage_show(&ru0))));
+
+       return istat;
+}
+
+/*
+ *     vac_cleanup_one_index() -- do post-vacuum cleanup for index relation.
+ *
+ * Returns bulk delete stats derived from input stats
+ */
+IndexBulkDeleteResult *
+vac_cleanup_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat)
+{
+       PGRUsage        ru0;
+
+       pg_rusage_init(&ru0);
+
+       istat = index_vacuum_cleanup(ivinfo, istat);
+
+       if (istat)
+       {
+               ereport(ivinfo->message_level,
+                               (errmsg("index \"%s\" now contains %.0f row versions in %u pages",
+                                               RelationGetRelationName(ivinfo->index),
+                                               istat->num_index_tuples,
+                                               istat->num_pages),
+                                errdetail("%.0f index row versions were removed.\n"
+                                                  "%u index pages were newly deleted.\n"
+                                                  "%u index pages are currently deleted, of which %u are currently reusable.\n"
+                                                  "%s.",
+                                                  istat->tuples_removed,
+                                                  istat->pages_newly_deleted,
+                                                  istat->pages_deleted, istat->pages_free,
+                                                  pg_rusage_show(&ru0))));
+       }
+
+       return istat;
+}
+
+/*
+ * Returns the total required space for VACUUM's dead_items array given a
+ * max_items value.
+ */
+inline Size
+vac_max_items_to_alloc_size(int max_items)
+{
+       Assert(max_items <= MAXDEADITEMS(MaxAllocSize));
+
+       return offsetof(VacDeadItems, items) + sizeof(ItemPointerData) * max_items;
+}
+
+/*
+ *     vac_tid_reaped() -- is a particular tid deletable?
+ *
+ *             This has the right signature to be an IndexBulkDeleteCallback.
+ *
+ *             Assumes dead_items array is sorted (in ascending TID order).
+ */
+static bool
+vac_tid_reaped(ItemPointer itemptr, void *state)
+{
+       VacDeadItems *dead_items = (VacDeadItems *) state;
+       int64           litem,
+                               ritem,
+                               item;
+       ItemPointer res;
+
+       litem = itemptr_encode(&dead_items->items[0]);
+       ritem = itemptr_encode(&dead_items->items[dead_items->num_items - 1]);
+       item = itemptr_encode(itemptr);
+
+       /*
+        * Doing a simple bound check before bsearch() is useful to avoid the
+        * extra cost of bsearch(), especially if dead items on the heap are
+        * concentrated in a certain range.  Since this function is called for
+        * every index tuple, it pays to be really fast.
+        */
+       if (item < litem || item > ritem)
+               return false;
+
+       res = (ItemPointer) bsearch((void *) itemptr,
+                                                               (void *) dead_items->items,
+                                                               dead_items->num_items,
+                                                               sizeof(ItemPointerData),
+                                                               vac_cmp_itemptr);
+
+       return (res != NULL);
+}
+
+/*
+ * Comparator routines for use with qsort() and bsearch().
+ */
+static int
+vac_cmp_itemptr(const void *left, const void *right)
+{
+       BlockNumber lblk,
+                               rblk;
+       OffsetNumber loff,
+                               roff;
+
+       lblk = ItemPointerGetBlockNumber((ItemPointer) left);
+       rblk = ItemPointerGetBlockNumber((ItemPointer) right);
+
+       if (lblk < rblk)
+               return -1;
+       if (lblk > rblk)
+               return 1;
+
+       loff = ItemPointerGetOffsetNumber((ItemPointer) left);
+       roff = ItemPointerGetOffsetNumber((ItemPointer) right);
+
+       if (loff < roff)
+               return -1;
+       if (loff > roff)
+               return 1;
+
+       return 0;
+}
index 4cfd52eaf4d847977995220905c0bde478924e36..97bffa8ff198fec925e1fa3cbbf80bef3369309b 100644 (file)
@@ -15,6 +15,7 @@
 #define VACUUM_H
 
 #include "access/htup.h"
+#include "access/genam.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
@@ -230,6 +231,21 @@ typedef struct VacuumParams
        int                     nworkers;
 } VacuumParams;
 
+/*
+ * VacDeadItems stores TIDs whose index tuples are deleted by index vacuuming.
+ */
+typedef struct VacDeadItems
+{
+       int                     max_items;              /* # slots allocated in array */
+       int                     num_items;              /* current # of entries */
+
+       /* Sorted array of TIDs to delete from indexes */
+       ItemPointerData items[FLEXIBLE_ARRAY_MEMBER];
+} VacDeadItems;
+
+#define MAXDEADITEMS(avail_mem) \
+       (((avail_mem) - offsetof(VacDeadItems, items)) / sizeof(ItemPointerData))
+
 /* GUC parameters */
 extern PGDLLIMPORT int default_statistics_target;      /* PGDLLIMPORT for PostGIS */
 extern int     vacuum_freeze_min_age;
@@ -282,6 +298,12 @@ extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple,
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
                                                                         bits32 options, bool verbose,
                                                                         LOCKMODE lmode);
+extern IndexBulkDeleteResult *vac_bulkdel_one_index(IndexVacuumInfo *ivinfo,
+                                                                                                       IndexBulkDeleteResult *istat,
+                                                                                                       VacDeadItems *dead_items);
+extern IndexBulkDeleteResult *vac_cleanup_one_index(IndexVacuumInfo *ivinfo,
+                                                                                                       IndexBulkDeleteResult *istat);
+extern Size vac_max_items_to_alloc_size(int max_items);
 
 /* in commands/analyze.c */
 extern void analyze_rel(Oid relid, RangeVar *relation,
index 0c61ccbdd0a8e0964b0d7590c1dfb5a7fb424ab4..98635087912475b9dc39a288a1c69f839731771b 100644 (file)
@@ -1305,7 +1305,6 @@ LPVOID
 LPWSTR
 LSEG
 LUID
-LVDeadTuples
 LVPagePruneState
 LVParallelIndStats
 LVParallelIndVacStatus
@@ -2800,6 +2799,7 @@ UserMapping
 UserOpts
 VacAttrStats
 VacAttrStatsP
+VacDeadItems
 VacErrPhase
 VacOptValue
 VacuumParams