LCOV - code coverage report
Current view: top level - contrib/bloom - blvacuum.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 92 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 2 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * blvacuum.c
       4              :  *              Bloom VACUUM functions.
       5              :  *
       6              :  * Copyright (c) 2016-2026, 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            0 : blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
      31              :                          IndexBulkDeleteCallback callback, void *callback_state)
      32              : {
      33            0 :         Relation        index = info->index;
      34            0 :         BlockNumber blkno,
      35              :                                 npages;
      36            0 :         FreeBlockNumberArray notFullPage;
      37            0 :         int                     countPage = 0;
      38            0 :         BloomState      state;
      39            0 :         Buffer          buffer;
      40            0 :         Page            page;
      41            0 :         BloomMetaPageData *metaData;
      42            0 :         GenericXLogState *gxlogState;
      43              : 
      44            0 :         if (stats == NULL)
      45            0 :                 stats = palloc0_object(IndexBulkDeleteResult);
      46              : 
      47            0 :         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            0 :         npages = RelationGetNumberOfBlocks(index);
      54            0 :         for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
      55              :         {
      56            0 :                 BloomTuple *itup,
      57              :                                    *itupPtr,
      58              :                                    *itupEnd;
      59              : 
      60            0 :                 vacuum_delay_point(false);
      61              : 
      62            0 :                 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
      63            0 :                                                                         RBM_NORMAL, info->strategy);
      64              : 
      65            0 :                 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
      66            0 :                 gxlogState = GenericXLogStart(index);
      67            0 :                 page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
      68              : 
      69              :                 /* Ignore empty/deleted pages until blvacuumcleanup() */
      70            0 :                 if (PageIsNew(page) || BloomPageIsDeleted(page))
      71              :                 {
      72            0 :                         UnlockReleaseBuffer(buffer);
      73            0 :                         GenericXLogAbort(gxlogState);
      74            0 :                         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            0 :                 itup = itupPtr = BloomPageGetTuple(&state, page, FirstOffsetNumber);
      82            0 :                 itupEnd = BloomPageGetTuple(&state, page,
      83              :                                                                         OffsetNumberNext(BloomPageGetMaxOffset(page)));
      84            0 :                 while (itup < itupEnd)
      85              :                 {
      86              :                         /* Do we have to delete this tuple? */
      87            0 :                         if (callback(&itup->heapPtr, callback_state))
      88              :                         {
      89              :                                 /* Yes; adjust count of tuples that will be left on page */
      90            0 :                                 BloomPageGetOpaque(page)->maxoff--;
      91            0 :                                 stats->tuples_removed += 1;
      92            0 :                         }
      93              :                         else
      94              :                         {
      95              :                                 /* No; copy it to itupPtr++, but skip copy if not needed */
      96            0 :                                 if (itupPtr != itup)
      97            0 :                                         memmove(itupPtr, itup, state.sizeOfBloomTuple);
      98            0 :                                 itupPtr = BloomPageGetNextTuple(&state, itupPtr);
      99              :                         }
     100              : 
     101            0 :                         itup = BloomPageGetNextTuple(&state, itup);
     102              :                 }
     103              : 
     104              :                 /* Assert that we counted correctly */
     105            0 :                 Assert(itupPtr == BloomPageGetTuple(&state, page,
     106              :                                                                                         OffsetNumberNext(BloomPageGetMaxOffset(page))));
     107              : 
     108              :                 /*
     109              :                  * Add page to new notFullPage list if we will not mark page as
     110              :                  * deleted and there is free space on it
     111              :                  */
     112            0 :                 if (BloomPageGetMaxOffset(page) != 0 &&
     113            0 :                         BloomPageGetFreeSpace(&state, page) >= state.sizeOfBloomTuple &&
     114            0 :                         countPage < BloomMetaBlockN)
     115            0 :                         notFullPage[countPage++] = blkno;
     116              : 
     117              :                 /* Did we delete something? */
     118            0 :                 if (itupPtr != itup)
     119              :                 {
     120              :                         /* Is it empty page now? */
     121            0 :                         if (BloomPageGetMaxOffset(page) == 0)
     122            0 :                                 BloomPageSetDeleted(page);
     123              :                         /* Adjust pd_lower */
     124            0 :                         ((PageHeader) page)->pd_lower = (char *) itupPtr - page;
     125              :                         /* Finish WAL-logging */
     126            0 :                         GenericXLogFinish(gxlogState);
     127            0 :                 }
     128              :                 else
     129              :                 {
     130              :                         /* Didn't change anything: abort WAL-logging */
     131            0 :                         GenericXLogAbort(gxlogState);
     132              :                 }
     133            0 :                 UnlockReleaseBuffer(buffer);
     134            0 :         }
     135              : 
     136              :         /*
     137              :          * Update the metapage's notFullPage list with whatever we found.  Our
     138              :          * info could already be out of date at this point, but blinsert() will
     139              :          * cope if so.
     140              :          */
     141            0 :         buffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
     142            0 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
     143              : 
     144            0 :         gxlogState = GenericXLogStart(index);
     145            0 :         page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
     146              : 
     147            0 :         metaData = BloomPageGetMeta(page);
     148            0 :         memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
     149            0 :         metaData->nStart = 0;
     150            0 :         metaData->nEnd = countPage;
     151              : 
     152            0 :         GenericXLogFinish(gxlogState);
     153            0 :         UnlockReleaseBuffer(buffer);
     154              : 
     155            0 :         return stats;
     156            0 : }
     157              : 
     158              : /*
     159              :  * Post-VACUUM cleanup.
     160              :  *
     161              :  * Result: a palloc'd struct containing statistical info for VACUUM displays.
     162              :  */
     163              : IndexBulkDeleteResult *
     164            0 : blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
     165              : {
     166            0 :         Relation        index = info->index;
     167            0 :         BlockNumber npages,
     168              :                                 blkno;
     169              : 
     170            0 :         if (info->analyze_only)
     171            0 :                 return stats;
     172              : 
     173            0 :         if (stats == NULL)
     174            0 :                 stats = palloc0_object(IndexBulkDeleteResult);
     175              : 
     176              :         /*
     177              :          * Iterate over the pages: insert deleted pages into FSM and collect
     178              :          * statistics.
     179              :          */
     180            0 :         npages = RelationGetNumberOfBlocks(index);
     181            0 :         stats->num_pages = npages;
     182            0 :         stats->pages_free = 0;
     183            0 :         stats->num_index_tuples = 0;
     184            0 :         for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
     185              :         {
     186            0 :                 Buffer          buffer;
     187            0 :                 Page            page;
     188              : 
     189            0 :                 vacuum_delay_point(false);
     190              : 
     191            0 :                 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
     192            0 :                                                                         RBM_NORMAL, info->strategy);
     193            0 :                 LockBuffer(buffer, BUFFER_LOCK_SHARE);
     194            0 :                 page = BufferGetPage(buffer);
     195              : 
     196            0 :                 if (PageIsNew(page) || BloomPageIsDeleted(page))
     197              :                 {
     198            0 :                         RecordFreeIndexPage(index, blkno);
     199            0 :                         stats->pages_free++;
     200            0 :                 }
     201              :                 else
     202              :                 {
     203            0 :                         stats->num_index_tuples += BloomPageGetMaxOffset(page);
     204              :                 }
     205              : 
     206            0 :                 UnlockReleaseBuffer(buffer);
     207            0 :         }
     208              : 
     209            0 :         IndexFreeSpaceMapVacuum(info->index);
     210              : 
     211            0 :         return stats;
     212            0 : }
        

Generated by: LCOV version 2.3.2-1