LCOV - differential code coverage report
Current view: top level - contrib/bloom - blinsert.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 93.3 % 119 111 8 111
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 7 7 7
Baseline: lcov-20250906-005545-baseline Branches: 54.8 % 42 23 19 23
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 1 1 1
(360..) days: 93.2 % 118 110 8 110
Function coverage date bins:
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 6 6 6
Branch coverage date bins:
(360..) days: 54.8 % 42 23 19 23

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * blinsert.c
                                  4                 :                :  *      Bloom index build and insert functions.
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2016-2025, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *    contrib/bloom/blinsert.c
                                 10                 :                :  *
                                 11                 :                :  *-------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : #include "postgres.h"
                                 14                 :                : 
                                 15                 :                : #include "access/genam.h"
                                 16                 :                : #include "access/generic_xlog.h"
                                 17                 :                : #include "access/tableam.h"
                                 18                 :                : #include "bloom.h"
                                 19                 :                : #include "miscadmin.h"
                                 20                 :                : #include "nodes/execnodes.h"
                                 21                 :                : #include "storage/bufmgr.h"
                                 22                 :                : #include "utils/memutils.h"
                                 23                 :                : #include "utils/rel.h"
                                 24                 :                : 
  164 tgl@sss.pgh.pa.us          25                 :CBC         126 : PG_MODULE_MAGIC_EXT(
                                 26                 :                :                     .name = "bloom",
                                 27                 :                :                     .version = PG_VERSION
                                 28                 :                : );
                                 29                 :                : 
                                 30                 :                : /*
                                 31                 :                :  * State of bloom index build.  We accumulate one page data here before
                                 32                 :                :  * flushing it to buffer manager.
                                 33                 :                :  */
                                 34                 :                : typedef struct
                                 35                 :                : {
                                 36                 :                :     BloomState  blstate;        /* bloom index state */
                                 37                 :                :     int64       indtuples;      /* total number of tuples indexed */
                                 38                 :                :     MemoryContext tmpCtx;       /* temporary memory context reset after each
                                 39                 :                :                                  * tuple */
                                 40                 :                :     PGAlignedBlock data;        /* cached page */
                                 41                 :                :     int         count;          /* number of tuples in cached page */
                                 42                 :                : } BloomBuildState;
                                 43                 :                : 
                                 44                 :                : /*
                                 45                 :                :  * Flush page cached in BloomBuildState.
                                 46                 :                :  */
                                 47                 :                : static void
 3445 teodor@sigaev.ru           48                 :             36 : flushCachedPage(Relation index, BloomBuildState *buildstate)
                                 49                 :                : {
                                 50                 :                :     Page        page;
                                 51                 :             36 :     Buffer      buffer = BloomNewBuffer(index);
                                 52                 :                :     GenericXLogState *state;
                                 53                 :                : 
                                 54                 :             36 :     state = GenericXLogStart(index);
 3434 tgl@sss.pgh.pa.us          55                 :             36 :     page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
 2562                            56                 :             36 :     memcpy(page, buildstate->data.data, BLCKSZ);
 3445 teodor@sigaev.ru           57                 :             36 :     GenericXLogFinish(state);
                                 58                 :             36 :     UnlockReleaseBuffer(buffer);
                                 59                 :             36 : }
                                 60                 :                : 
                                 61                 :                : /*
                                 62                 :                :  * (Re)initialize cached page in BloomBuildState.
                                 63                 :                :  */
                                 64                 :                : static void
                                 65                 :             36 : initCachedPage(BloomBuildState *buildstate)
                                 66                 :                : {
 2562 tgl@sss.pgh.pa.us          67                 :             36 :     BloomInitPage(buildstate->data.data, 0);
 3445 teodor@sigaev.ru           68                 :             36 :     buildstate->count = 0;
                                 69                 :             36 : }
                                 70                 :                : 
                                 71                 :                : /*
                                 72                 :                :  * Per-tuple callback for table_index_build_scan.
                                 73                 :                :  */
                                 74                 :                : static void
 2129 andres@anarazel.de         75                 :          18750 : bloomBuildCallback(Relation index, ItemPointer tid, Datum *values,
                                 76                 :                :                    bool *isnull, bool tupleIsAlive, void *state)
                                 77                 :                : {
 3445 teodor@sigaev.ru           78                 :          18750 :     BloomBuildState *buildstate = (BloomBuildState *) state;
                                 79                 :                :     MemoryContext oldCtx;
                                 80                 :                :     BloomTuple *itup;
                                 81                 :                : 
                                 82                 :          18750 :     oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
                                 83                 :                : 
 2129 andres@anarazel.de         84                 :          18750 :     itup = BloomFormTuple(&buildstate->blstate, tid, values, isnull);
                                 85                 :                : 
                                 86                 :                :     /* Try to add next item to cached page */
 2562 tgl@sss.pgh.pa.us          87         [ +  + ]:          18750 :     if (BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
                                 88                 :                :     {
                                 89                 :                :         /* Next item was added successfully */
 3445 teodor@sigaev.ru           90                 :          18719 :         buildstate->count++;
                                 91                 :                :     }
                                 92                 :                :     else
                                 93                 :                :     {
                                 94                 :                :         /* Cached page is full, flush it out and make a new one */
                                 95                 :             31 :         flushCachedPage(index, buildstate);
                                 96                 :                : 
                                 97         [ -  + ]:             31 :         CHECK_FOR_INTERRUPTS();
                                 98                 :                : 
                                 99                 :             31 :         initCachedPage(buildstate);
                                100                 :                : 
 2562 tgl@sss.pgh.pa.us         101         [ -  + ]:             31 :         if (!BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
                                102                 :                :         {
                                103                 :                :             /* We shouldn't be here since we're inserting to the empty page */
 3443 tgl@sss.pgh.pa.us         104         [ #  # ]:UBC           0 :             elog(ERROR, "could not add new bloom tuple to empty page");
                                105                 :                :         }
                                106                 :                : 
                                107                 :                :         /* Next item was added successfully */
 2725 tgl@sss.pgh.pa.us         108                 :CBC          31 :         buildstate->count++;
                                109                 :                :     }
                                110                 :                : 
                                111                 :                :     /* Update total tuple count */
                                112                 :          18750 :     buildstate->indtuples += 1;
                                113                 :                : 
 3445 teodor@sigaev.ru          114                 :          18750 :     MemoryContextSwitchTo(oldCtx);
                                115                 :          18750 :     MemoryContextReset(buildstate->tmpCtx);
                                116                 :          18750 : }
                                117                 :                : 
                                118                 :                : /*
                                119                 :                :  * Build a new bloom index.
                                120                 :                :  */
                                121                 :                : IndexBuildResult *
                                122                 :              5 : blbuild(Relation heap, Relation index, IndexInfo *indexInfo)
                                123                 :                : {
                                124                 :                :     IndexBuildResult *result;
                                125                 :                :     double      reltuples;
                                126                 :                :     BloomBuildState buildstate;
                                127                 :                : 
                                128         [ -  + ]:              5 :     if (RelationGetNumberOfBlocks(index) != 0)
 3445 teodor@sigaev.ru          129         [ #  # ]:UBC           0 :         elog(ERROR, "index \"%s\" already contains data",
                                130                 :                :              RelationGetRelationName(index));
                                131                 :                : 
                                132                 :                :     /* Initialize the meta page */
  745 heikki.linnakangas@i      133                 :CBC           5 :     BloomInitMetapage(index, MAIN_FORKNUM);
                                134                 :                : 
                                135                 :                :     /* Initialize the bloom build state */
 3445 teodor@sigaev.ru          136                 :              5 :     memset(&buildstate, 0, sizeof(buildstate));
                                137                 :              5 :     initBloomState(&buildstate.blstate, index);
                                138                 :              5 :     buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
                                139                 :                :                                               "Bloom build temporary context",
                                140                 :                :                                               ALLOCSET_DEFAULT_SIZES);
                                141                 :              5 :     initCachedPage(&buildstate);
                                142                 :                : 
                                143                 :                :     /* Do the heap scan */
 2349 alvherre@alvh.no-ip.      144                 :              5 :     reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
                                145                 :                :                                        bloomBuildCallback, &buildstate,
                                146                 :                :                                        NULL);
                                147                 :                : 
                                148                 :                :     /* Flush last page if needed (it will be, unless heap was empty) */
 3445 teodor@sigaev.ru          149         [ +  - ]:              5 :     if (buildstate.count > 0)
                                150                 :              5 :         flushCachedPage(index, &buildstate);
                                151                 :                : 
                                152                 :              5 :     MemoryContextDelete(buildstate.tmpCtx);
                                153                 :                : 
                                154                 :              5 :     result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
 2725 tgl@sss.pgh.pa.us         155                 :              5 :     result->heap_tuples = reltuples;
                                156                 :              5 :     result->index_tuples = buildstate.indtuples;
                                157                 :                : 
 3445 teodor@sigaev.ru          158                 :              5 :     return result;
                                159                 :                : }
                                160                 :                : 
                                161                 :                : /*
                                162                 :                :  * Build an empty bloom index in the initialization fork.
                                163                 :                :  */
                                164                 :                : void
                                165                 :              1 : blbuildempty(Relation index)
                                166                 :                : {
                                167                 :                :     /* Initialize the meta page */
  745 heikki.linnakangas@i      168                 :              1 :     BloomInitMetapage(index, INIT_FORKNUM);
 3445 teodor@sigaev.ru          169                 :              1 : }
                                170                 :                : 
                                171                 :                : /*
                                172                 :                :  * Insert new tuple to the bloom index.
                                173                 :                :  */
                                174                 :                : bool
                                175                 :         104000 : blinsert(Relation index, Datum *values, bool *isnull,
                                176                 :                :          ItemPointer ht_ctid, Relation heapRel,
                                177                 :                :          IndexUniqueCheck checkUnique,
                                178                 :                :          bool indexUnchanged,
                                179                 :                :          IndexInfo *indexInfo)
                                180                 :                : {
                                181                 :                :     BloomState  blstate;
                                182                 :                :     BloomTuple *itup;
                                183                 :                :     MemoryContext oldCtx;
                                184                 :                :     MemoryContext insertCtx;
                                185                 :                :     BloomMetaPageData *metaData;
                                186                 :                :     Buffer      buffer,
                                187                 :                :                 metaBuffer;
                                188                 :                :     Page        page,
                                189                 :                :                 metaPage;
                                190                 :         104000 :     BlockNumber blkno = InvalidBlockNumber;
                                191                 :                :     OffsetNumber nStart;
                                192                 :                :     GenericXLogState *state;
                                193                 :                : 
                                194                 :         104000 :     insertCtx = AllocSetContextCreate(CurrentMemoryContext,
                                195                 :                :                                       "Bloom insert temporary context",
                                196                 :                :                                       ALLOCSET_DEFAULT_SIZES);
                                197                 :                : 
                                198                 :         104000 :     oldCtx = MemoryContextSwitchTo(insertCtx);
                                199                 :                : 
                                200                 :         104000 :     initBloomState(&blstate, index);
                                201                 :         104000 :     itup = BloomFormTuple(&blstate, ht_ctid, values, isnull);
                                202                 :                : 
                                203                 :                :     /*
                                204                 :                :      * At first, try to insert new tuple to the first page in notFullPage
                                205                 :                :      * array.  If successful, we don't need to modify the meta page.
                                206                 :                :      */
                                207                 :         104000 :     metaBuffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
                                208                 :         104000 :     LockBuffer(metaBuffer, BUFFER_LOCK_SHARE);
 3426 kgrittn@postgresql.o      209                 :         104000 :     metaData = BloomPageGetMeta(BufferGetPage(metaBuffer));
                                210                 :                : 
 3445 teodor@sigaev.ru          211         [ +  + ]:         104000 :     if (metaData->nEnd > metaData->nStart)
                                212                 :                :     {
                                213                 :         103999 :         blkno = metaData->notFullPage[metaData->nStart];
                                214         [ -  + ]:         103999 :         Assert(blkno != InvalidBlockNumber);
                                215                 :                : 
                                216                 :                :         /* Don't hold metabuffer lock while doing insert */
                                217                 :         103999 :         LockBuffer(metaBuffer, BUFFER_LOCK_UNLOCK);
                                218                 :                : 
                                219                 :         103999 :         buffer = ReadBuffer(index, blkno);
                                220                 :         103999 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
                                221                 :                : 
                                222                 :         103999 :         state = GenericXLogStart(index);
 3434 tgl@sss.pgh.pa.us         223                 :         103999 :         page = GenericXLogRegisterBuffer(state, buffer, 0);
                                224                 :                : 
                                225                 :                :         /*
                                226                 :                :          * We might have found a page that was recently deleted by VACUUM.  If
                                227                 :                :          * so, we can reuse it, but we must reinitialize it.
                                228                 :                :          */
 3311                           229   [ +  -  -  + ]:         103999 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
 3311 tgl@sss.pgh.pa.us         230                 :UBC           0 :             BloomInitPage(page, 0);
                                231                 :                : 
 3445 teodor@sigaev.ru          232         [ +  + ]:CBC      103999 :         if (BloomPageAddItem(&blstate, page, itup))
                                233                 :                :         {
                                234                 :                :             /* Success!  Apply the change, clean up, and exit */
                                235                 :         103242 :             GenericXLogFinish(state);
                                236                 :         103242 :             UnlockReleaseBuffer(buffer);
                                237                 :         103242 :             ReleaseBuffer(metaBuffer);
                                238                 :         103242 :             MemoryContextSwitchTo(oldCtx);
                                239                 :         103242 :             MemoryContextDelete(insertCtx);
                                240                 :         103242 :             return false;
                                241                 :                :         }
                                242                 :                : 
                                243                 :                :         /* Didn't fit, must try other pages */
 3437 tgl@sss.pgh.pa.us         244                 :            757 :         GenericXLogAbort(state);
                                245                 :            757 :         UnlockReleaseBuffer(buffer);
                                246                 :                :     }
                                247                 :                :     else
                                248                 :                :     {
                                249                 :                :         /* No entries in notFullPage */
 3445 teodor@sigaev.ru          250                 :              1 :         LockBuffer(metaBuffer, BUFFER_LOCK_UNLOCK);
                                251                 :                :     }
                                252                 :                : 
                                253                 :                :     /*
                                254                 :                :      * Try other pages in notFullPage array.  We will have to change nStart in
                                255                 :                :      * metapage.  Thus, grab exclusive lock on metapage.
                                256                 :                :      */
                                257                 :            758 :     LockBuffer(metaBuffer, BUFFER_LOCK_EXCLUSIVE);
                                258                 :                : 
                                259                 :                :     /* nStart might have changed while we didn't have lock */
                                260                 :            758 :     nStart = metaData->nStart;
                                261                 :                : 
                                262                 :                :     /* Skip first page if we already tried it above */
 3437 tgl@sss.pgh.pa.us         263         [ +  + ]:            758 :     if (nStart < metaData->nEnd &&
 3445 teodor@sigaev.ru          264         [ +  - ]:            757 :         blkno == metaData->notFullPage[nStart])
                                265                 :            757 :         nStart++;
                                266                 :                : 
                                267                 :                :     /*
                                268                 :                :      * This loop iterates for each page we try from the notFullPage array, and
                                269                 :                :      * will also initialize a GenericXLogState for the fallback case of having
                                270                 :                :      * to allocate a new page.
                                271                 :                :      */
                                272                 :                :     for (;;)
                                273                 :                :     {
 3437 tgl@sss.pgh.pa.us         274                 :            758 :         state = GenericXLogStart(index);
                                275                 :                : 
                                276                 :                :         /* get modifiable copy of metapage */
 3434                           277                 :            758 :         metaPage = GenericXLogRegisterBuffer(state, metaBuffer, 0);
 3437                           278                 :            758 :         metaData = BloomPageGetMeta(metaPage);
                                279                 :                : 
                                280         [ +  + ]:            758 :         if (nStart >= metaData->nEnd)
                                281                 :            113 :             break;              /* no more entries in notFullPage array */
                                282                 :                : 
 3445 teodor@sigaev.ru          283                 :            645 :         blkno = metaData->notFullPage[nStart];
                                284         [ -  + ]:            645 :         Assert(blkno != InvalidBlockNumber);
                                285                 :                : 
                                286                 :            645 :         buffer = ReadBuffer(index, blkno);
                                287                 :            645 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 3434 tgl@sss.pgh.pa.us         288                 :            645 :         page = GenericXLogRegisterBuffer(state, buffer, 0);
                                289                 :                : 
                                290                 :                :         /* Basically same logic as above */
 3311                           291   [ +  -  -  + ]:            645 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
 3311 tgl@sss.pgh.pa.us         292                 :UBC           0 :             BloomInitPage(page, 0);
                                293                 :                : 
 3445 teodor@sigaev.ru          294         [ +  - ]:CBC         645 :         if (BloomPageAddItem(&blstate, page, itup))
                                295                 :                :         {
                                296                 :                :             /* Success!  Apply the changes, clean up, and exit */
                                297                 :            645 :             metaData->nStart = nStart;
                                298                 :            645 :             GenericXLogFinish(state);
                                299                 :            645 :             UnlockReleaseBuffer(buffer);
                                300                 :            645 :             UnlockReleaseBuffer(metaBuffer);
                                301                 :            645 :             MemoryContextSwitchTo(oldCtx);
                                302                 :            645 :             MemoryContextDelete(insertCtx);
                                303                 :            645 :             return false;
                                304                 :                :         }
                                305                 :                : 
                                306                 :                :         /* Didn't fit, must try other pages */
 3437 tgl@sss.pgh.pa.us         307                 :UBC           0 :         GenericXLogAbort(state);
                                308                 :              0 :         UnlockReleaseBuffer(buffer);
 3445 teodor@sigaev.ru          309                 :              0 :         nStart++;
                                310                 :                :     }
                                311                 :                : 
                                312                 :                :     /*
                                313                 :                :      * Didn't find place to insert in notFullPage array.  Allocate new page.
                                314                 :                :      * (XXX is it good to do this while holding ex-lock on the metapage??)
                                315                 :                :      */
 3445 teodor@sigaev.ru          316                 :CBC         113 :     buffer = BloomNewBuffer(index);
                                317                 :                : 
 3434 tgl@sss.pgh.pa.us         318                 :            113 :     page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
 3445 teodor@sigaev.ru          319                 :            113 :     BloomInitPage(page, 0);
                                320                 :                : 
 3443 tgl@sss.pgh.pa.us         321         [ -  + ]:            113 :     if (!BloomPageAddItem(&blstate, page, itup))
                                322                 :                :     {
                                323                 :                :         /* We shouldn't be here since we're inserting to an empty page */
 3443 tgl@sss.pgh.pa.us         324         [ #  # ]:UBC           0 :         elog(ERROR, "could not add new bloom tuple to empty page");
                                325                 :                :     }
                                326                 :                : 
                                327                 :                :     /* Reset notFullPage array to contain just this new page */
 3445 teodor@sigaev.ru          328                 :CBC         113 :     metaData->nStart = 0;
                                329                 :            113 :     metaData->nEnd = 1;
                                330                 :            113 :     metaData->notFullPage[0] = BufferGetBlockNumber(buffer);
                                331                 :                : 
                                332                 :                :     /* Apply the changes, clean up, and exit */
                                333                 :            113 :     GenericXLogFinish(state);
                                334                 :                : 
                                335                 :            113 :     UnlockReleaseBuffer(buffer);
                                336                 :            113 :     UnlockReleaseBuffer(metaBuffer);
                                337                 :                : 
 3437 tgl@sss.pgh.pa.us         338                 :            113 :     MemoryContextSwitchTo(oldCtx);
                                339                 :            113 :     MemoryContextDelete(insertCtx);
                                340                 :                : 
 3445 teodor@sigaev.ru          341                 :            113 :     return false;
                                342                 :                : }
        

Generated by: LCOV version 2.4-beta