LCOV - code coverage report
Current view: top level - contrib/bloom - blvacuum.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 70 71 98.6 %
Date: 2024-03-29 00:11:46 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * blvacuum.c
       4             :  *      Bloom VACUUM functions.
       5             :  *
       6             :  * Copyright (c) 2016-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *    contrib/bloom/blvacuum.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/genam.h"
      16             : #include "bloom.h"
      17             : #include "catalog/storage.h"
      18             : #include "commands/vacuum.h"
      19             : #include "miscadmin.h"
      20             : #include "postmaster/autovacuum.h"
      21             : #include "storage/bufmgr.h"
      22             : #include "storage/indexfsm.h"
      23             : #include "storage/lmgr.h"
      24             : 
      25             : 
      26             : /*
      27             :  * Bulk deletion of all index entries pointing to a set of heap tuples.
      28             :  * The set of target tuples is specified via a callback routine that tells
      29             :  * whether any given heap tuple (identified by ItemPointer) is being deleted.
      30             :  *
      31             :  * Result: a palloc'd struct containing statistical info for VACUUM displays.
      32             :  */
      33             : IndexBulkDeleteResult *
      34          22 : blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
      35             :              IndexBulkDeleteCallback callback, void *callback_state)
      36             : {
      37          22 :     Relation    index = info->index;
      38             :     BlockNumber blkno,
      39             :                 npages;
      40             :     FreeBlockNumberArray notFullPage;
      41          22 :     int         countPage = 0;
      42             :     BloomState  state;
      43             :     Buffer      buffer;
      44             :     Page        page;
      45             :     BloomMetaPageData *metaData;
      46             :     GenericXLogState *gxlogState;
      47             : 
      48          22 :     if (stats == NULL)
      49          22 :         stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
      50             : 
      51          22 :     initBloomState(&state, index);
      52             : 
      53             :     /*
      54             :      * Iterate over the pages. We don't care about concurrently added pages,
      55             :      * they can't contain tuples to delete.
      56             :      */
      57          22 :     npages = RelationGetNumberOfBlocks(index);
      58        1356 :     for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
      59             :     {
      60             :         BloomTuple *itup,
      61             :                    *itupPtr,
      62             :                    *itupEnd;
      63             : 
      64        1334 :         vacuum_delay_point();
      65             : 
      66        1334 :         buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
      67             :                                     RBM_NORMAL, info->strategy);
      68             : 
      69        1334 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
      70        1334 :         gxlogState = GenericXLogStart(index);
      71        1334 :         page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
      72             : 
      73             :         /* Ignore empty/deleted pages until blvacuumcleanup() */
      74        1334 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
      75             :         {
      76           8 :             UnlockReleaseBuffer(buffer);
      77           8 :             GenericXLogAbort(gxlogState);
      78           8 :             continue;
      79             :         }
      80             : 
      81             :         /*
      82             :          * Iterate over the tuples.  itup points to current tuple being
      83             :          * scanned, itupPtr points to where to save next non-deleted tuple.
      84             :          */
      85        1326 :         itup = itupPtr = BloomPageGetTuple(&state, page, FirstOffsetNumber);
      86        1326 :         itupEnd = BloomPageGetTuple(&state, page,
      87             :                                     OffsetNumberNext(BloomPageGetMaxOffset(page)));
      88      673326 :         while (itup < itupEnd)
      89             :         {
      90             :             /* Do we have to delete this tuple? */
      91      672000 :             if (callback(&itup->heapPtr, callback_state))
      92             :             {
      93             :                 /* Yes; adjust count of tuples that will be left on page */
      94       97250 :                 BloomPageGetOpaque(page)->maxoff--;
      95       97250 :                 stats->tuples_removed += 1;
      96             :             }
      97             :             else
      98             :             {
      99             :                 /* No; copy it to itupPtr++, but skip copy if not needed */
     100      574750 :                 if (itupPtr != itup)
     101      568158 :                     memmove((Pointer) itupPtr, (Pointer) itup,
     102             :                             state.sizeOfBloomTuple);
     103      574750 :                 itupPtr = BloomPageGetNextTuple(&state, itupPtr);
     104             :             }
     105             : 
     106      672000 :             itup = BloomPageGetNextTuple(&state, itup);
     107             :         }
     108             : 
     109             :         /* Assert that we counted correctly */
     110             :         Assert(itupPtr == BloomPageGetTuple(&state, page,
     111             :                                             OffsetNumberNext(BloomPageGetMaxOffset(page))));
     112             : 
     113             :         /*
     114             :          * Add page to new notFullPage list if we will not mark page as
     115             :          * deleted and there is free space on it
     116             :          */
     117        1326 :         if (BloomPageGetMaxOffset(page) != 0 &&
     118        1318 :             BloomPageGetFreeSpace(&state, page) >= state.sizeOfBloomTuple &&
     119        1312 :             countPage < BloomMetaBlockN)
     120        1312 :             notFullPage[countPage++] = blkno;
     121             : 
     122             :         /* Did we delete something? */
     123        1326 :         if (itupPtr != itup)
     124             :         {
     125             :             /* Is it empty page now? */
     126        1318 :             if (BloomPageGetMaxOffset(page) == 0)
     127           8 :                 BloomPageSetDeleted(page);
     128             :             /* Adjust pd_lower */
     129        1318 :             ((PageHeader) page)->pd_lower = (Pointer) itupPtr - page;
     130             :             /* Finish WAL-logging */
     131        1318 :             GenericXLogFinish(gxlogState);
     132             :         }
     133             :         else
     134             :         {
     135             :             /* Didn't change anything: abort WAL-logging */
     136           8 :             GenericXLogAbort(gxlogState);
     137             :         }
     138        1326 :         UnlockReleaseBuffer(buffer);
     139             :     }
     140             : 
     141             :     /*
     142             :      * Update the metapage's notFullPage list with whatever we found.  Our
     143             :      * info could already be out of date at this point, but blinsert() will
     144             :      * cope if so.
     145             :      */
     146          22 :     buffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
     147          22 :     LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
     148             : 
     149          22 :     gxlogState = GenericXLogStart(index);
     150          22 :     page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
     151             : 
     152          22 :     metaData = BloomPageGetMeta(page);
     153          22 :     memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
     154          22 :     metaData->nStart = 0;
     155          22 :     metaData->nEnd = countPage;
     156             : 
     157          22 :     GenericXLogFinish(gxlogState);
     158          22 :     UnlockReleaseBuffer(buffer);
     159             : 
     160          22 :     return stats;
     161             : }
     162             : 
     163             : /*
     164             :  * Post-VACUUM cleanup.
     165             :  *
     166             :  * Result: a palloc'd struct containing statistical info for VACUUM displays.
     167             :  */
     168             : IndexBulkDeleteResult *
     169          24 : blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
     170             : {
     171          24 :     Relation    index = info->index;
     172             :     BlockNumber npages,
     173             :                 blkno;
     174             : 
     175          24 :     if (info->analyze_only)
     176           0 :         return stats;
     177             : 
     178          24 :     if (stats == NULL)
     179           2 :         stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
     180             : 
     181             :     /*
     182             :      * Iterate over the pages: insert deleted pages into FSM and collect
     183             :      * statistics.
     184             :      */
     185          24 :     npages = RelationGetNumberOfBlocks(index);
     186          24 :     stats->num_pages = npages;
     187          24 :     stats->pages_free = 0;
     188          24 :     stats->num_index_tuples = 0;
     189        1574 :     for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
     190             :     {
     191             :         Buffer      buffer;
     192             :         Page        page;
     193             : 
     194        1550 :         vacuum_delay_point();
     195             : 
     196        1550 :         buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
     197             :                                     RBM_NORMAL, info->strategy);
     198        1550 :         LockBuffer(buffer, BUFFER_LOCK_SHARE);
     199        1550 :         page = (Page) BufferGetPage(buffer);
     200             : 
     201        1550 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
     202             :         {
     203          16 :             RecordFreeIndexPage(index, blkno);
     204          16 :             stats->pages_free++;
     205             :         }
     206             :         else
     207             :         {
     208        1534 :             stats->num_index_tuples += BloomPageGetMaxOffset(page);
     209             :         }
     210             : 
     211        1550 :         UnlockReleaseBuffer(buffer);
     212             :     }
     213             : 
     214          24 :     IndexFreeSpaceMapVacuum(info->index);
     215             : 
     216          24 :     return stats;
     217             : }

Generated by: LCOV version 1.14