LCOV - differential code coverage report
Current view: top level - src/backend/access/spgist - spginsert.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 98.6 % 69 68 1 4 64 4
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 4 4 1 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * spginsert.c
       4                 :  *    Externally visible index creation/insertion routines
       5                 :  *
       6                 :  * All the actual insertion logic is in spgdoinsert.c.
       7                 :  *
       8                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       9                 :  * Portions Copyright (c) 1994, Regents of the University of California
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *          src/backend/access/spgist/spginsert.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : 
      17                 : #include "postgres.h"
      18                 : 
      19                 : #include "access/genam.h"
      20                 : #include "access/spgist_private.h"
      21                 : #include "access/spgxlog.h"
      22                 : #include "access/tableam.h"
      23                 : #include "access/xlog.h"
      24                 : #include "access/xloginsert.h"
      25                 : #include "catalog/index.h"
      26                 : #include "miscadmin.h"
      27                 : #include "storage/bufmgr.h"
      28                 : #include "storage/smgr.h"
      29                 : #include "utils/memutils.h"
      30                 : #include "utils/rel.h"
      31                 : 
      32                 : 
      33                 : typedef struct
      34                 : {
      35                 :     SpGistState spgstate;       /* SPGiST's working state */
      36                 :     int64       indtuples;      /* total number of tuples indexed */
      37                 :     MemoryContext tmpCtx;       /* per-tuple temporary context */
      38                 : } SpGistBuildState;
      39                 : 
      40                 : 
      41                 : /* Callback to process one heap tuple during table_index_build_scan */
      42                 : static void
      43 CBC      281361 : spgistBuildCallback(Relation index, ItemPointer tid, Datum *values,
      44                 :                     bool *isnull, bool tupleIsAlive, void *state)
      45                 : {
      46          281361 :     SpGistBuildState *buildstate = (SpGistBuildState *) state;
      47                 :     MemoryContext oldCtx;
      48                 : 
      49                 :     /* Work in temp context, and reset it after each tuple */
      50          281361 :     oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
      51                 : 
      52                 :     /*
      53                 :      * Even though no concurrent insertions can be happening, we still might
      54                 :      * get a buffer-locking failure due to bgwriter or checkpointer taking a
      55                 :      * lock on some buffer.  So we need to be willing to retry.  We can flush
      56                 :      * any temp data when retrying.
      57                 :      */
      58          281363 :     while (!spgdoinsert(index, &buildstate->spgstate, tid,
      59                 :                         values, isnull))
      60                 :     {
      61               2 :         MemoryContextReset(buildstate->tmpCtx);
      62                 :     }
      63                 : 
      64                 :     /* Update total tuple count */
      65          281361 :     buildstate->indtuples += 1;
      66                 : 
      67          281361 :     MemoryContextSwitchTo(oldCtx);
      68          281361 :     MemoryContextReset(buildstate->tmpCtx);
      69          281361 : }
      70                 : 
      71                 : /*
      72                 :  * Build an SP-GiST index.
      73                 :  */
      74                 : IndexBuildResult *
      75             100 : spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
      76                 : {
      77                 :     IndexBuildResult *result;
      78                 :     double      reltuples;
      79                 :     SpGistBuildState buildstate;
      80                 :     Buffer      metabuffer,
      81                 :                 rootbuffer,
      82                 :                 nullbuffer;
      83                 : 
      84             100 :     if (RelationGetNumberOfBlocks(index) != 0)
      85 UBC           0 :         elog(ERROR, "index \"%s\" already contains data",
      86                 :              RelationGetRelationName(index));
      87                 : 
      88                 :     /*
      89                 :      * Initialize the meta page and root pages
      90                 :      */
      91 CBC         100 :     metabuffer = SpGistNewBuffer(index);
      92             100 :     rootbuffer = SpGistNewBuffer(index);
      93             100 :     nullbuffer = SpGistNewBuffer(index);
      94                 : 
      95             100 :     Assert(BufferGetBlockNumber(metabuffer) == SPGIST_METAPAGE_BLKNO);
      96             100 :     Assert(BufferGetBlockNumber(rootbuffer) == SPGIST_ROOT_BLKNO);
      97             100 :     Assert(BufferGetBlockNumber(nullbuffer) == SPGIST_NULL_BLKNO);
      98                 : 
      99             100 :     START_CRIT_SECTION();
     100                 : 
     101             100 :     SpGistInitMetapage(BufferGetPage(metabuffer));
     102             100 :     MarkBufferDirty(metabuffer);
     103             100 :     SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
     104             100 :     MarkBufferDirty(rootbuffer);
     105             100 :     SpGistInitBuffer(nullbuffer, SPGIST_LEAF | SPGIST_NULLS);
     106             100 :     MarkBufferDirty(nullbuffer);
     107                 : 
     108                 : 
     109             100 :     END_CRIT_SECTION();
     110                 : 
     111             100 :     UnlockReleaseBuffer(metabuffer);
     112             100 :     UnlockReleaseBuffer(rootbuffer);
     113             100 :     UnlockReleaseBuffer(nullbuffer);
     114                 : 
     115                 :     /*
     116                 :      * Now insert all the heap data into the index
     117                 :      */
     118             100 :     initSpGistState(&buildstate.spgstate, index);
     119             100 :     buildstate.spgstate.isBuild = true;
     120             100 :     buildstate.indtuples = 0;
     121                 : 
     122             100 :     buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
     123                 :                                               "SP-GiST build temporary context",
     124                 :                                               ALLOCSET_DEFAULT_SIZES);
     125                 : 
     126             100 :     reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
     127                 :                                        spgistBuildCallback, (void *) &buildstate,
     128                 :                                        NULL);
     129                 : 
     130             100 :     MemoryContextDelete(buildstate.tmpCtx);
     131                 : 
     132             100 :     SpGistUpdateMetaPage(index);
     133                 : 
     134                 :     /*
     135                 :      * We didn't write WAL records as we built the index, so if WAL-logging is
     136                 :      * required, write all pages to the WAL now.
     137                 :      */
     138             100 :     if (RelationNeedsWAL(index))
     139                 :     {
     140              34 :         log_newpage_range(index, MAIN_FORKNUM,
     141                 :                           0, RelationGetNumberOfBlocks(index),
     142                 :                           true);
     143                 :     }
     144                 : 
     145             100 :     result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
     146             100 :     result->heap_tuples = reltuples;
     147             100 :     result->index_tuples = buildstate.indtuples;
     148                 : 
     149             100 :     return result;
     150                 : }
     151                 : 
     152                 : /*
     153                 :  * Build an empty SPGiST index in the initialization fork
     154                 :  */
     155                 : void
     156               4 : spgbuildempty(Relation index)
     157                 : {
     158                 :     Page        page;
     159                 : 
     160                 :     /* Construct metapage. */
     161 GNC           4 :     page = (Page) palloc_aligned(BLCKSZ, PG_IO_ALIGN_SIZE, 0);
     162 CBC           4 :     SpGistInitMetapage(page);
     163                 : 
     164                 :     /*
     165                 :      * Write the page and log it unconditionally.  This is important
     166                 :      * particularly for indexes created on tablespaces and databases whose
     167                 :      * creation happened after the last redo pointer as recovery removes any
     168                 :      * of their existing content when the corresponding create records are
     169                 :      * replayed.
     170                 :      */
     171               4 :     PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO);
     172               4 :     smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, SPGIST_METAPAGE_BLKNO,
     173                 :               page, true);
     174 GNC           4 :     log_newpage(&(RelationGetSmgr(index))->smgr_rlocator.locator, INIT_FORKNUM,
     175                 :                 SPGIST_METAPAGE_BLKNO, page, true);
     176                 : 
     177                 :     /* Likewise for the root page. */
     178 CBC           4 :     SpGistInitPage(page, SPGIST_LEAF);
     179                 : 
     180               4 :     PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO);
     181               4 :     smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, SPGIST_ROOT_BLKNO,
     182                 :               page, true);
     183 GNC           4 :     log_newpage(&(RelationGetSmgr(index))->smgr_rlocator.locator, INIT_FORKNUM,
     184                 :                 SPGIST_ROOT_BLKNO, page, true);
     185                 : 
     186                 :     /* Likewise for the null-tuples root page. */
     187 CBC           4 :     SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
     188                 : 
     189               4 :     PageSetChecksumInplace(page, SPGIST_NULL_BLKNO);
     190               4 :     smgrwrite(RelationGetSmgr(index), INIT_FORKNUM, SPGIST_NULL_BLKNO,
     191                 :               page, true);
     192 GNC           4 :     log_newpage(&(RelationGetSmgr(index))->smgr_rlocator.locator, INIT_FORKNUM,
     193                 :                 SPGIST_NULL_BLKNO, page, true);
     194                 : 
     195                 :     /*
     196                 :      * An immediate sync is required even if we xlog'd the pages, because the
     197                 :      * writes did not go through shared buffers and therefore a concurrent
     198                 :      * checkpoint may have moved the redo pointer past our xlog record.
     199                 :      */
     200 CBC           4 :     smgrimmedsync(RelationGetSmgr(index), INIT_FORKNUM);
     201               4 : }
     202                 : 
     203                 : /*
     204                 :  * Insert one new tuple into an SPGiST index.
     205                 :  */
     206                 : bool
     207          121225 : spginsert(Relation index, Datum *values, bool *isnull,
     208                 :           ItemPointer ht_ctid, Relation heapRel,
     209                 :           IndexUniqueCheck checkUnique,
     210                 :           bool indexUnchanged,
     211                 :           IndexInfo *indexInfo)
     212                 : {
     213                 :     SpGistState spgstate;
     214                 :     MemoryContext oldCtx;
     215                 :     MemoryContext insertCtx;
     216                 : 
     217          121225 :     insertCtx = AllocSetContextCreate(CurrentMemoryContext,
     218                 :                                       "SP-GiST insert temporary context",
     219                 :                                       ALLOCSET_DEFAULT_SIZES);
     220          121225 :     oldCtx = MemoryContextSwitchTo(insertCtx);
     221                 : 
     222          121225 :     initSpGistState(&spgstate, index);
     223                 : 
     224                 :     /*
     225                 :      * We might have to repeat spgdoinsert() multiple times, if conflicts
     226                 :      * occur with concurrent insertions.  If so, reset the insertCtx each time
     227                 :      * to avoid cumulative memory consumption.  That means we also have to
     228                 :      * redo initSpGistState(), but it's cheap enough not to matter.
     229                 :      */
     230          121821 :     while (!spgdoinsert(index, &spgstate, ht_ctid, values, isnull))
     231                 :     {
     232             596 :         MemoryContextReset(insertCtx);
     233             596 :         initSpGistState(&spgstate, index);
     234                 :     }
     235                 : 
     236          121223 :     SpGistUpdateMetaPage(index);
     237                 : 
     238          121223 :     MemoryContextSwitchTo(oldCtx);
     239          121223 :     MemoryContextDelete(insertCtx);
     240                 : 
     241                 :     /* return false since we've not done any unique check */
     242          121223 :     return false;
     243                 : }
        

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