LCOV - differential code coverage report
Current view: top level - contrib/bloom - blinsert.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.5 % 124 116 2 3 3 33 2 81 5 29 4
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 7 7 2 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (240..) days: 93.5 % 123 115 2 3 3 33 1 81 5 29
Function coverage date bins:
(240..) days: 100.0 % 7 7 2 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * blinsert.c
                                  4                 :  *      Bloom index build and insert functions.
                                  5                 :  *
                                  6                 :  * Copyright (c) 2016-2023, 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 "catalog/index.h"
                                 20                 : #include "miscadmin.h"
                                 21                 : #include "storage/bufmgr.h"
                                 22                 : #include "storage/indexfsm.h"
                                 23                 : #include "storage/smgr.h"
                                 24                 : #include "utils/memutils.h"
                                 25                 : #include "utils/rel.h"
                                 26                 : 
 2564 teodor                     27 CBC          95 : PG_MODULE_MAGIC;
                                 28                 : 
                                 29                 : /*
                                 30                 :  * State of bloom index build.  We accumulate one page data here before
                                 31                 :  * flushing it to buffer manager.
                                 32                 :  */
                                 33                 : typedef struct
                                 34                 : {
                                 35                 :     BloomState  blstate;        /* bloom index state */
                                 36                 :     int64       indtuples;      /* total number of tuples indexed */
                                 37                 :     MemoryContext tmpCtx;       /* temporary memory context reset after each
                                 38                 :                                  * tuple */
                                 39                 :     PGAlignedBlock data;        /* cached page */
                                 40                 :     int         count;          /* number of tuples in cached page */
                                 41                 : } BloomBuildState;
                                 42                 : 
                                 43                 : /*
                                 44                 :  * Flush page cached in BloomBuildState.
                                 45                 :  */
                                 46                 : static void
                                 47             213 : flushCachedPage(Relation index, BloomBuildState *buildstate)
                                 48                 : {
                                 49                 :     Page        page;
                                 50             213 :     Buffer      buffer = BloomNewBuffer(index);
                                 51                 :     GenericXLogState *state;
                                 52                 : 
                                 53             213 :     state = GenericXLogStart(index);
 2553 tgl                        54             213 :     page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
 1681                            55             213 :     memcpy(page, buildstate->data.data, BLCKSZ);
 2564 teodor                     56             213 :     GenericXLogFinish(state);
                                 57             213 :     UnlockReleaseBuffer(buffer);
                                 58             213 : }
                                 59                 : 
                                 60                 : /*
                                 61                 :  * (Re)initialize cached page in BloomBuildState.
                                 62                 :  */
                                 63                 : static void
                                 64             213 : initCachedPage(BloomBuildState *buildstate)
                                 65                 : {
 1681 tgl                        66             213 :     BloomInitPage(buildstate->data.data, 0);
 2564 teodor                     67             213 :     buildstate->count = 0;
                                 68             213 : }
                                 69                 : 
                                 70                 : /*
                                 71                 :  * Per-tuple callback for table_index_build_scan.
                                 72                 :  */
                                 73                 : static void
 1248 andres                     74          108758 : bloomBuildCallback(Relation index, ItemPointer tid, Datum *values,
                                 75                 :                    bool *isnull, bool tupleIsAlive, void *state)
                                 76                 : {
 2564 teodor                     77          108758 :     BloomBuildState *buildstate = (BloomBuildState *) state;
                                 78                 :     MemoryContext oldCtx;
                                 79                 :     BloomTuple *itup;
                                 80                 : 
                                 81          108758 :     oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
                                 82                 : 
 1248 andres                     83          108758 :     itup = BloomFormTuple(&buildstate->blstate, tid, values, isnull);
                                 84                 : 
                                 85                 :     /* Try to add next item to cached page */
 1681 tgl                        86          108758 :     if (BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
                                 87                 :     {
                                 88                 :         /* Next item was added successfully */
 2564 teodor                     89          108550 :         buildstate->count++;
                                 90                 :     }
                                 91                 :     else
                                 92                 :     {
                                 93                 :         /* Cached page is full, flush it out and make a new one */
                                 94             208 :         flushCachedPage(index, buildstate);
                                 95                 : 
                                 96             208 :         CHECK_FOR_INTERRUPTS();
                                 97                 : 
                                 98             208 :         initCachedPage(buildstate);
                                 99                 : 
 1681 tgl                       100             208 :         if (!BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
                                101                 :         {
                                102                 :             /* We shouldn't be here since we're inserting to the empty page */
 2562 tgl                       103 UBC           0 :             elog(ERROR, "could not add new bloom tuple to empty page");
                                104                 :         }
                                105                 : 
                                106                 :         /* Next item was added successfully */
 1844 tgl                       107 CBC         208 :         buildstate->count++;
                                108                 :     }
                                109                 : 
                                110                 :     /* Update total tuple count */
                                111          108758 :     buildstate->indtuples += 1;
                                112                 : 
 2564 teodor                    113          108758 :     MemoryContextSwitchTo(oldCtx);
                                114          108758 :     MemoryContextReset(buildstate->tmpCtx);
                                115          108758 : }
                                116                 : 
                                117                 : /*
                                118                 :  * Build a new bloom index.
                                119                 :  */
                                120                 : IndexBuildResult *
                                121               5 : blbuild(Relation heap, Relation index, IndexInfo *indexInfo)
                                122                 : {
                                123                 :     IndexBuildResult *result;
                                124                 :     double      reltuples;
                                125                 :     BloomBuildState buildstate;
                                126                 : 
                                127               5 :     if (RelationGetNumberOfBlocks(index) != 0)
 2564 teodor                    128 UBC           0 :         elog(ERROR, "index \"%s\" already contains data",
                                129                 :              RelationGetRelationName(index));
                                130                 : 
                                131                 :     /* Initialize the meta page */
 2564 teodor                    132 CBC           5 :     BloomInitMetapage(index);
                                133                 : 
                                134                 :     /* Initialize the bloom build state */
                                135               5 :     memset(&buildstate, 0, sizeof(buildstate));
                                136               5 :     initBloomState(&buildstate.blstate, index);
                                137               5 :     buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
                                138                 :                                               "Bloom build temporary context",
                                139                 :                                               ALLOCSET_DEFAULT_SIZES);
                                140               5 :     initCachedPage(&buildstate);
                                141                 : 
                                142                 :     /* Do the heap scan */
 1468 alvherre                  143               5 :     reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
                                144                 :                                        bloomBuildCallback, (void *) &buildstate,
                                145                 :                                        NULL);
                                146                 : 
                                147                 :     /* Flush last page if needed (it will be, unless heap was empty) */
 2564 teodor                    148               5 :     if (buildstate.count > 0)
                                149               5 :         flushCachedPage(index, &buildstate);
                                150                 : 
                                151               5 :     MemoryContextDelete(buildstate.tmpCtx);
                                152                 : 
                                153               5 :     result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
 1844 tgl                       154               5 :     result->heap_tuples = reltuples;
                                155               5 :     result->index_tuples = buildstate.indtuples;
                                156                 : 
 2564 teodor                    157               5 :     return result;
                                158                 : }
                                159                 : 
                                160                 : /*
                                161                 :  * Build an empty bloom index in the initialization fork.
                                162                 :  */
                                163                 : void
                                164               1 : blbuildempty(Relation index)
                                165                 : {
                                166                 :     Page        metapage;
                                167                 : 
                                168                 :     /* Construct metapage. */
    1 tmunro                    169 GNC           1 :     metapage = (Page) palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE, 0);
 2511 tgl                       170 CBC           1 :     BloomFillMetapage(index, metapage);
                                171                 : 
                                172                 :     /*
                                173                 :      * Write the page and log it.  It might seem that an immediate sync would
                                174                 :      * be sufficient to guarantee that the file exists on disk, but recovery
                                175                 :      * itself might remove it while replaying, for example, an
                                176                 :      * XLOG_DBASE_CREATE* or XLOG_TBLSPC_CREATE record.  Therefore, we need
                                177                 :      * this even when wal_level=minimal.
                                178                 :      */
                                179               1 :     PageSetChecksumInplace(metapage, BLOOM_METAPAGE_BLKNO);
  636                           180               1 :     smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, BLOOM_METAPAGE_BLKNO,
                                181                 :               metapage, true);
  277 rhaas                     182 GNC           1 :     log_newpage(&(RelationGetSmgr(index))->smgr_rlocator.locator, INIT_FORKNUM,
                                183                 :                 BLOOM_METAPAGE_BLKNO, metapage, true);
                                184                 : 
                                185                 :     /*
                                186                 :      * An immediate sync is required even if we xlog'd the page, because the
                                187                 :      * write did not go through shared_buffers and therefore a concurrent
                                188                 :      * checkpoint may have moved the redo pointer past our xlog record.
                                189                 :      */
  636 tgl                       190 CBC           1 :     smgrimmedsync(RelationGetSmgr(index), INIT_FORKNUM);
 2564 teodor                    191               1 : }
                                192                 : 
                                193                 : /*
                                194                 :  * Insert new tuple to the bloom index.
                                195                 :  */
                                196                 : bool
                                197          104000 : blinsert(Relation index, Datum *values, bool *isnull,
                                198                 :          ItemPointer ht_ctid, Relation heapRel,
                                199                 :          IndexUniqueCheck checkUnique,
                                200                 :          bool indexUnchanged,
                                201                 :          IndexInfo *indexInfo)
                                202                 : {
                                203                 :     BloomState  blstate;
                                204                 :     BloomTuple *itup;
                                205                 :     MemoryContext oldCtx;
                                206                 :     MemoryContext insertCtx;
                                207                 :     BloomMetaPageData *metaData;
                                208                 :     Buffer      buffer,
                                209                 :                 metaBuffer;
                                210                 :     Page        page,
                                211                 :                 metaPage;
                                212          104000 :     BlockNumber blkno = InvalidBlockNumber;
                                213                 :     OffsetNumber nStart;
                                214                 :     GenericXLogState *state;
                                215                 : 
                                216          104000 :     insertCtx = AllocSetContextCreate(CurrentMemoryContext,
                                217                 :                                       "Bloom insert temporary context",
                                218                 :                                       ALLOCSET_DEFAULT_SIZES);
                                219                 : 
                                220          104000 :     oldCtx = MemoryContextSwitchTo(insertCtx);
                                221                 : 
                                222          104000 :     initBloomState(&blstate, index);
                                223          104000 :     itup = BloomFormTuple(&blstate, ht_ctid, values, isnull);
                                224                 : 
                                225                 :     /*
                                226                 :      * At first, try to insert new tuple to the first page in notFullPage
                                227                 :      * array.  If successful, we don't need to modify the meta page.
                                228                 :      */
                                229          104000 :     metaBuffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
                                230          104000 :     LockBuffer(metaBuffer, BUFFER_LOCK_SHARE);
 2545 kgrittn                   231          104000 :     metaData = BloomPageGetMeta(BufferGetPage(metaBuffer));
                                232                 : 
 2564 teodor                    233          104000 :     if (metaData->nEnd > metaData->nStart)
                                234                 :     {
 2564 teodor                    235 GIC      103999 :         blkno = metaData->notFullPage[metaData->nStart];
                                236          103999 :         Assert(blkno != InvalidBlockNumber);
 2556 tgl                       237 ECB             : 
                                238                 :         /* Don't hold metabuffer lock while doing insert */
 2564 teodor                    239 CBC      103999 :         LockBuffer(metaBuffer, BUFFER_LOCK_UNLOCK);
 2564 teodor                    240 ECB             : 
 2564 teodor                    241 GIC      103999 :         buffer = ReadBuffer(index, blkno);
 2564 teodor                    242 CBC      103999 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 2556 tgl                       243 ECB             : 
 2564 teodor                    244 GIC      103999 :         state = GenericXLogStart(index);
 2553 tgl                       245          103999 :         page = GenericXLogRegisterBuffer(state, buffer, 0);
                                246                 : 
                                247                 :         /*
                                248                 :          * We might have found a page that was recently deleted by VACUUM.  If
 2430 tgl                       249 ECB             :          * so, we can reuse it, but we must reinitialize it.
 2430 tgl                       250 EUB             :          */
 2430 tgl                       251 GIC      103999 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
 2430 tgl                       252 LBC           0 :             BloomInitPage(page, 0);
                                253                 : 
 2564 teodor                    254 GIC      103999 :         if (BloomPageAddItem(&blstate, page, itup))
 2564 teodor                    255 ECB             :         {
 2556 tgl                       256                 :             /* Success!  Apply the change, clean up, and exit */
 2564 teodor                    257 CBC      102712 :             GenericXLogFinish(state);
                                258          102712 :             UnlockReleaseBuffer(buffer);
                                259          102712 :             ReleaseBuffer(metaBuffer);
                                260          102712 :             MemoryContextSwitchTo(oldCtx);
 2564 teodor                    261 GIC      102712 :             MemoryContextDelete(insertCtx);
                                262          102712 :             return false;
                                263                 :         }
 2556 tgl                       264 ECB             : 
                                265                 :         /* Didn't fit, must try other pages */
 2556 tgl                       266 GIC        1287 :         GenericXLogAbort(state);
                                267            1287 :         UnlockReleaseBuffer(buffer);
                                268                 :     }
                                269                 :     else
 2564 teodor                    270 ECB             :     {
                                271                 :         /* No entries in notFullPage */
 2564 teodor                    272 GIC           1 :         LockBuffer(metaBuffer, BUFFER_LOCK_UNLOCK);
                                273                 :     }
                                274                 : 
                                275                 :     /*
                                276                 :      * Try other pages in notFullPage array.  We will have to change nStart in
 2564 teodor                    277 ECB             :      * metapage.  Thus, grab exclusive lock on metapage.
                                278                 :      */
 2564 teodor                    279 GIC        1288 :     LockBuffer(metaBuffer, BUFFER_LOCK_EXCLUSIVE);
 2564 teodor                    280 ECB             : 
                                281                 :     /* nStart might have changed while we didn't have lock */
 2564 teodor                    282 GIC        1288 :     nStart = metaData->nStart;
 2556 tgl                       283 ECB             : 
                                284                 :     /* Skip first page if we already tried it above */
 2556 tgl                       285 CBC        1288 :     if (nStart < metaData->nEnd &&
 2564 teodor                    286 GIC        1287 :         blkno == metaData->notFullPage[nStart])
                                287            1287 :         nStart++;
                                288                 : 
                                289                 :     /*
                                290                 :      * This loop iterates for each page we try from the notFullPage array, and
                                291                 :      * will also initialize a GenericXLogState for the fallback case of having
                                292                 :      * to allocate a new page.
                                293                 :      */
 2556 tgl                       294 ECB             :     for (;;)
                                295                 :     {
 2556 tgl                       296 GIC        1288 :         state = GenericXLogStart(index);
 2556 tgl                       297 ECB             : 
                                298                 :         /* get modifiable copy of metapage */
 2553 tgl                       299 GIC        1288 :         metaPage = GenericXLogRegisterBuffer(state, metaBuffer, 0);
 2556 tgl                       300 CBC        1288 :         metaData = BloomPageGetMeta(metaPage);
 2556 tgl                       301 ECB             : 
 2556 tgl                       302 GIC        1288 :         if (nStart >= metaData->nEnd)
 2556 tgl                       303 CBC           5 :             break;              /* no more entries in notFullPage array */
 2556 tgl                       304 ECB             : 
 2564 teodor                    305 GIC        1283 :         blkno = metaData->notFullPage[nStart];
 2564 teodor                    306 CBC        1283 :         Assert(blkno != InvalidBlockNumber);
 2564 teodor                    307 ECB             : 
 2564 teodor                    308 CBC        1283 :         buffer = ReadBuffer(index, blkno);
 2564 teodor                    309 GIC        1283 :         LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
 2553 tgl                       310            1283 :         page = GenericXLogRegisterBuffer(state, buffer, 0);
 2564 teodor                    311 ECB             : 
 2430 tgl                       312 EUB             :         /* Basically same logic as above */
 2430 tgl                       313 GIC        1283 :         if (PageIsNew(page) || BloomPageIsDeleted(page))
 2430 tgl                       314 LBC           0 :             BloomInitPage(page, 0);
                                315                 : 
 2564 teodor                    316 GIC        1283 :         if (BloomPageAddItem(&blstate, page, itup))
 2564 teodor                    317 ECB             :         {
 2556 tgl                       318                 :             /* Success!  Apply the changes, clean up, and exit */
 2564 teodor                    319 CBC        1283 :             metaData->nStart = nStart;
                                320            1283 :             GenericXLogFinish(state);
                                321            1283 :             UnlockReleaseBuffer(buffer);
                                322            1283 :             UnlockReleaseBuffer(metaBuffer);
                                323            1283 :             MemoryContextSwitchTo(oldCtx);
 2564 teodor                    324 GIC        1283 :             MemoryContextDelete(insertCtx);
                                325            1283 :             return false;
                                326                 :         }
 2556 tgl                       327 EUB             : 
                                328                 :         /* Didn't fit, must try other pages */
 2556 tgl                       329 UBC           0 :         GenericXLogAbort(state);
 2556 tgl                       330 UIC           0 :         UnlockReleaseBuffer(buffer);
 2564 teodor                    331               0 :         nStart++;
                                332                 :     }
                                333                 : 
                                334                 :     /*
                                335                 :      * Didn't find place to insert in notFullPage array.  Allocate new page.
 2556 tgl                       336 ECB             :      * (XXX is it good to do this while holding ex-lock on the metapage??)
                                337                 :      */
 2564 teodor                    338 CBC           5 :     buffer = BloomNewBuffer(index);
 2564 teodor                    339 ECB             : 
 2553 tgl                       340 GIC           5 :     page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
 2564 teodor                    341 CBC           5 :     BloomInitPage(page, 0);
                                342                 : 
 2562 tgl                       343 GIC           5 :     if (!BloomPageAddItem(&blstate, page, itup))
 2562 tgl                       344 EUB             :     {
                                345                 :         /* We shouldn't be here since we're inserting to an empty page */
 2562 tgl                       346 UIC           0 :         elog(ERROR, "could not add new bloom tuple to empty page");
                                347                 :     }
 2564 teodor                    348 ECB             : 
 2556 tgl                       349                 :     /* Reset notFullPage array to contain just this new page */
 2564 teodor                    350 CBC           5 :     metaData->nStart = 0;
 2564 teodor                    351 GIC           5 :     metaData->nEnd = 1;
                                352               5 :     metaData->notFullPage[0] = BufferGetBlockNumber(buffer);
 2564 teodor                    353 ECB             : 
                                354                 :     /* Apply the changes, clean up, and exit */
 2564 teodor                    355 CBC           5 :     GenericXLogFinish(state);
 2564 teodor                    356 ECB             : 
 2564 teodor                    357 GIC           5 :     UnlockReleaseBuffer(buffer);
 2564 teodor                    358 CBC           5 :     UnlockReleaseBuffer(metaBuffer);
 2564 teodor                    359 ECB             : 
 2556 tgl                       360 GIC           5 :     MemoryContextSwitchTo(oldCtx);
 2556 tgl                       361 CBC           5 :     MemoryContextDelete(insertCtx);
                                362                 : 
 2564 teodor                    363 GIC           5 :     return false;
                                364                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a