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

Generated by: LCOV version 1.14