LCOV - code coverage report
Current view: top level - src/backend/storage/buffer - localbuf.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 138 165 83.6 %
Date: 2020-05-31 23:07:13 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * localbuf.c
       4             :  *    local buffer manager. Fast buffer manager for temporary tables,
       5             :  *    which never need to be WAL-logged or checkpointed, etc.
       6             :  *
       7             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994-5, Regents of the University of California
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/storage/buffer/localbuf.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include "access/parallel.h"
      19             : #include "catalog/catalog.h"
      20             : #include "executor/instrument.h"
      21             : #include "storage/buf_internals.h"
      22             : #include "storage/bufmgr.h"
      23             : #include "utils/guc.h"
      24             : #include "utils/memutils.h"
      25             : #include "utils/resowner_private.h"
      26             : 
      27             : 
      28             : /*#define LBDEBUG*/
      29             : 
      30             : /* entry for buffer lookup hashtable */
      31             : typedef struct
      32             : {
      33             :     BufferTag   key;            /* Tag of a disk page */
      34             :     int         id;             /* Associated local buffer's index */
      35             : } LocalBufferLookupEnt;
      36             : 
      37             : /* Note: this macro only works on local buffers, not shared ones! */
      38             : #define LocalBufHdrGetBlock(bufHdr) \
      39             :     LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]
      40             : 
      41             : int         NLocBuffer = 0;     /* until buffers are initialized */
      42             : 
      43             : BufferDesc *LocalBufferDescriptors = NULL;
      44             : Block      *LocalBufferBlockPointers = NULL;
      45             : int32      *LocalRefCount = NULL;
      46             : 
      47             : static int  nextFreeLocalBuf = 0;
      48             : 
      49             : static HTAB *LocalBufHash = NULL;
      50             : 
      51             : 
      52             : static void InitLocalBuffers(void);
      53             : static Block GetLocalBufferStorage(void);
      54             : 
      55             : 
      56             : /*
      57             :  * PrefetchLocalBuffer -
      58             :  *    initiate asynchronous read of a block of a relation
      59             :  *
      60             :  * Do PrefetchBuffer's work for temporary relations.
      61             :  * No-op if prefetching isn't compiled in.
      62             :  */
      63             : PrefetchBufferResult
      64         212 : PrefetchLocalBuffer(SMgrRelation smgr, ForkNumber forkNum,
      65             :                     BlockNumber blockNum)
      66             : {
      67         212 :     PrefetchBufferResult result = {InvalidBuffer, false};
      68             :     BufferTag   newTag;         /* identity of requested block */
      69             :     LocalBufferLookupEnt *hresult;
      70             : 
      71         212 :     INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
      72             : 
      73             :     /* Initialize local buffers if first request in this session */
      74         212 :     if (LocalBufHash == NULL)
      75           0 :         InitLocalBuffers();
      76             : 
      77             :     /* See if the desired buffer already exists */
      78             :     hresult = (LocalBufferLookupEnt *)
      79         212 :         hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
      80             : 
      81         212 :     if (hresult)
      82             :     {
      83             :         /* Yes, so nothing to do */
      84         212 :         result.recent_buffer = -hresult->id - 1;
      85             :     }
      86             :     else
      87             :     {
      88             : #ifdef USE_PREFETCH
      89             :         /* Not in buffers, so initiate prefetch */
      90           0 :         smgrprefetch(smgr, forkNum, blockNum);
      91           0 :         result.initiated_io = true;
      92             : #endif                          /* USE_PREFETCH */
      93             :     }
      94             : 
      95         212 :     return result;
      96             : }
      97             : 
      98             : 
      99             : /*
     100             :  * LocalBufferAlloc -
     101             :  *    Find or create a local buffer for the given page of the given relation.
     102             :  *
     103             :  * API is similar to bufmgr.c's BufferAlloc, except that we do not need
     104             :  * to do any locking since this is all local.   Also, IO_IN_PROGRESS
     105             :  * does not get set.  Lastly, we support only default access strategy
     106             :  * (hence, usage_count is always advanced).
     107             :  */
     108             : BufferDesc *
     109      571944 : LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum,
     110             :                  bool *foundPtr)
     111             : {
     112             :     BufferTag   newTag;         /* identity of requested block */
     113             :     LocalBufferLookupEnt *hresult;
     114             :     BufferDesc *bufHdr;
     115             :     int         b;
     116             :     int         trycounter;
     117             :     bool        found;
     118             :     uint32      buf_state;
     119             : 
     120      571944 :     INIT_BUFFERTAG(newTag, smgr->smgr_rnode.node, forkNum, blockNum);
     121             : 
     122             :     /* Initialize local buffers if first request in this session */
     123      571944 :     if (LocalBufHash == NULL)
     124         264 :         InitLocalBuffers();
     125             : 
     126             :     /* See if the desired buffer already exists */
     127             :     hresult = (LocalBufferLookupEnt *)
     128      571944 :         hash_search(LocalBufHash, (void *) &newTag, HASH_FIND, NULL);
     129             : 
     130      571944 :     if (hresult)
     131             :     {
     132      557878 :         b = hresult->id;
     133      557878 :         bufHdr = GetLocalBufferDescriptor(b);
     134             :         Assert(BUFFERTAGS_EQUAL(bufHdr->tag, newTag));
     135             : #ifdef LBDEBUG
     136             :         fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
     137             :                 smgr->smgr_rnode.node.relNode, forkNum, blockNum, -b - 1);
     138             : #endif
     139      557878 :         buf_state = pg_atomic_read_u32(&bufHdr->state);
     140             : 
     141             :         /* this part is equivalent to PinBuffer for a shared buffer */
     142      557878 :         if (LocalRefCount[b] == 0)
     143             :         {
     144      553948 :             if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
     145             :             {
     146       46582 :                 buf_state += BUF_USAGECOUNT_ONE;
     147       46582 :                 pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     148             :             }
     149             :         }
     150      557878 :         LocalRefCount[b]++;
     151      557878 :         ResourceOwnerRememberBuffer(CurrentResourceOwner,
     152      557878 :                                     BufferDescriptorGetBuffer(bufHdr));
     153      557878 :         if (buf_state & BM_VALID)
     154      557878 :             *foundPtr = true;
     155             :         else
     156             :         {
     157             :             /* Previous read attempt must have failed; try again */
     158           0 :             *foundPtr = false;
     159             :         }
     160      557878 :         return bufHdr;
     161             :     }
     162             : 
     163             : #ifdef LBDEBUG
     164             :     fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
     165             :             smgr->smgr_rnode.node.relNode, forkNum, blockNum,
     166             :             -nextFreeLocalBuf - 1);
     167             : #endif
     168             : 
     169             :     /*
     170             :      * Need to get a new buffer.  We use a clock sweep algorithm (essentially
     171             :      * the same as what freelist.c does now...)
     172             :      */
     173       14066 :     trycounter = NLocBuffer;
     174             :     for (;;)
     175             :     {
     176        1052 :         b = nextFreeLocalBuf;
     177             : 
     178       15118 :         if (++nextFreeLocalBuf >= NLocBuffer)
     179           4 :             nextFreeLocalBuf = 0;
     180             : 
     181       15118 :         bufHdr = GetLocalBufferDescriptor(b);
     182             : 
     183       15118 :         if (LocalRefCount[b] == 0)
     184             :         {
     185       15118 :             buf_state = pg_atomic_read_u32(&bufHdr->state);
     186             : 
     187       15118 :             if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
     188             :             {
     189        1052 :                 buf_state -= BUF_USAGECOUNT_ONE;
     190        1052 :                 pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     191        1052 :                 trycounter = NLocBuffer;
     192             :             }
     193             :             else
     194             :             {
     195             :                 /* Found a usable buffer */
     196       14066 :                 LocalRefCount[b]++;
     197       14066 :                 ResourceOwnerRememberBuffer(CurrentResourceOwner,
     198       14066 :                                             BufferDescriptorGetBuffer(bufHdr));
     199       14066 :                 break;
     200             :             }
     201             :         }
     202           0 :         else if (--trycounter == 0)
     203           0 :             ereport(ERROR,
     204             :                     (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
     205             :                      errmsg("no empty local buffer available")));
     206             :     }
     207             : 
     208             :     /*
     209             :      * this buffer is not referenced but it might still be dirty. if that's
     210             :      * the case, write it out before reusing it!
     211             :      */
     212       14066 :     if (buf_state & BM_DIRTY)
     213             :     {
     214             :         SMgrRelation oreln;
     215           0 :         Page        localpage = (char *) LocalBufHdrGetBlock(bufHdr);
     216             : 
     217             :         /* Find smgr relation for buffer */
     218           0 :         oreln = smgropen(bufHdr->tag.rnode, MyBackendId);
     219             : 
     220           0 :         PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
     221             : 
     222             :         /* And write... */
     223           0 :         smgrwrite(oreln,
     224             :                   bufHdr->tag.forkNum,
     225             :                   bufHdr->tag.blockNum,
     226             :                   localpage,
     227             :                   false);
     228             : 
     229             :         /* Mark not-dirty now in case we error out below */
     230           0 :         buf_state &= ~BM_DIRTY;
     231           0 :         pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     232             : 
     233           0 :         pgBufferUsage.local_blks_written++;
     234             :     }
     235             : 
     236             :     /*
     237             :      * lazy memory allocation: allocate space on first use of a buffer.
     238             :      */
     239       14066 :     if (LocalBufHdrGetBlock(bufHdr) == NULL)
     240             :     {
     241             :         /* Set pointer for use by BufferGetBlock() macro */
     242       13014 :         LocalBufHdrGetBlock(bufHdr) = GetLocalBufferStorage();
     243             :     }
     244             : 
     245             :     /*
     246             :      * Update the hash table: remove old entry, if any, and make new one.
     247             :      */
     248       14066 :     if (buf_state & BM_TAG_VALID)
     249             :     {
     250             :         hresult = (LocalBufferLookupEnt *)
     251           0 :             hash_search(LocalBufHash, (void *) &bufHdr->tag,
     252             :                         HASH_REMOVE, NULL);
     253           0 :         if (!hresult)           /* shouldn't happen */
     254           0 :             elog(ERROR, "local buffer hash table corrupted");
     255             :         /* mark buffer invalid just in case hash insert fails */
     256           0 :         CLEAR_BUFFERTAG(bufHdr->tag);
     257           0 :         buf_state &= ~(BM_VALID | BM_TAG_VALID);
     258           0 :         pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     259             :     }
     260             : 
     261             :     hresult = (LocalBufferLookupEnt *)
     262       14066 :         hash_search(LocalBufHash, (void *) &newTag, HASH_ENTER, &found);
     263       14066 :     if (found)                  /* shouldn't happen */
     264           0 :         elog(ERROR, "local buffer hash table corrupted");
     265       14066 :     hresult->id = b;
     266             : 
     267             :     /*
     268             :      * it's all ours now.
     269             :      */
     270       14066 :     bufHdr->tag = newTag;
     271       14066 :     buf_state &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_IO_ERROR);
     272       14066 :     buf_state |= BM_TAG_VALID;
     273       14066 :     buf_state &= ~BUF_USAGECOUNT_MASK;
     274       14066 :     buf_state += BUF_USAGECOUNT_ONE;
     275       14066 :     pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     276             : 
     277       14066 :     *foundPtr = false;
     278       14066 :     return bufHdr;
     279             : }
     280             : 
     281             : /*
     282             :  * MarkLocalBufferDirty -
     283             :  *    mark a local buffer dirty
     284             :  */
     285             : void
     286     1354312 : MarkLocalBufferDirty(Buffer buffer)
     287             : {
     288             :     int         bufid;
     289             :     BufferDesc *bufHdr;
     290             :     uint32      buf_state;
     291             : 
     292             :     Assert(BufferIsLocal(buffer));
     293             : 
     294             : #ifdef LBDEBUG
     295             :     fprintf(stderr, "LB DIRTY %d\n", buffer);
     296             : #endif
     297             : 
     298     1354312 :     bufid = -(buffer + 1);
     299             : 
     300             :     Assert(LocalRefCount[bufid] > 0);
     301             : 
     302     1354312 :     bufHdr = GetLocalBufferDescriptor(bufid);
     303             : 
     304     1354312 :     buf_state = pg_atomic_read_u32(&bufHdr->state);
     305             : 
     306     1354312 :     if (!(buf_state & BM_DIRTY))
     307        9626 :         pgBufferUsage.local_blks_dirtied++;
     308             : 
     309     1354312 :     buf_state |= BM_DIRTY;
     310             : 
     311     1354312 :     pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     312     1354312 : }
     313             : 
     314             : /*
     315             :  * DropRelFileNodeLocalBuffers
     316             :  *      This function removes from the buffer pool all the pages of the
     317             :  *      specified relation that have block numbers >= firstDelBlock.
     318             :  *      (In particular, with firstDelBlock = 0, all pages are removed.)
     319             :  *      Dirty pages are simply dropped, without bothering to write them
     320             :  *      out first.  Therefore, this is NOT rollback-able, and so should be
     321             :  *      used only with extreme caution!
     322             :  *
     323             :  *      See DropRelFileNodeBuffers in bufmgr.c for more notes.
     324             :  */
     325             : void
     326         412 : DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
     327             :                             BlockNumber firstDelBlock)
     328             : {
     329             :     int         i;
     330             : 
     331      377244 :     for (i = 0; i < NLocBuffer; i++)
     332             :     {
     333      376832 :         BufferDesc *bufHdr = GetLocalBufferDescriptor(i);
     334             :         LocalBufferLookupEnt *hresult;
     335             :         uint32      buf_state;
     336             : 
     337      376832 :         buf_state = pg_atomic_read_u32(&bufHdr->state);
     338             : 
     339      376832 :         if ((buf_state & BM_TAG_VALID) &&
     340       27024 :             RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
     341          44 :             bufHdr->tag.forkNum == forkNum &&
     342          44 :             bufHdr->tag.blockNum >= firstDelBlock)
     343             :         {
     344          44 :             if (LocalRefCount[i] != 0)
     345           0 :                 elog(ERROR, "block %u of %s is still referenced (local %u)",
     346             :                      bufHdr->tag.blockNum,
     347             :                      relpathbackend(bufHdr->tag.rnode, MyBackendId,
     348             :                                     bufHdr->tag.forkNum),
     349             :                      LocalRefCount[i]);
     350             :             /* Remove entry from hashtable */
     351             :             hresult = (LocalBufferLookupEnt *)
     352          44 :                 hash_search(LocalBufHash, (void *) &bufHdr->tag,
     353             :                             HASH_REMOVE, NULL);
     354          44 :             if (!hresult)       /* shouldn't happen */
     355           0 :                 elog(ERROR, "local buffer hash table corrupted");
     356             :             /* Mark buffer invalid */
     357          44 :             CLEAR_BUFFERTAG(bufHdr->tag);
     358          44 :             buf_state &= ~BUF_FLAG_MASK;
     359          44 :             buf_state &= ~BUF_USAGECOUNT_MASK;
     360          44 :             pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     361             :         }
     362             :     }
     363         412 : }
     364             : 
     365             : /*
     366             :  * DropRelFileNodeAllLocalBuffers
     367             :  *      This function removes from the buffer pool all pages of all forks
     368             :  *      of the specified relation.
     369             :  *
     370             :  *      See DropRelFileNodesAllBuffers in bufmgr.c for more notes.
     371             :  */
     372             : void
     373        3196 : DropRelFileNodeAllLocalBuffers(RelFileNode rnode)
     374             : {
     375             :     int         i;
     376             : 
     377     3107964 :     for (i = 0; i < NLocBuffer; i++)
     378             :     {
     379     3104768 :         BufferDesc *bufHdr = GetLocalBufferDescriptor(i);
     380             :         LocalBufferLookupEnt *hresult;
     381             :         uint32      buf_state;
     382             : 
     383     3104768 :         buf_state = pg_atomic_read_u32(&bufHdr->state);
     384             : 
     385     3104768 :         if ((buf_state & BM_TAG_VALID) &&
     386      205906 :             RelFileNodeEquals(bufHdr->tag.rnode, rnode))
     387             :         {
     388       14022 :             if (LocalRefCount[i] != 0)
     389           0 :                 elog(ERROR, "block %u of %s is still referenced (local %u)",
     390             :                      bufHdr->tag.blockNum,
     391             :                      relpathbackend(bufHdr->tag.rnode, MyBackendId,
     392             :                                     bufHdr->tag.forkNum),
     393             :                      LocalRefCount[i]);
     394             :             /* Remove entry from hashtable */
     395             :             hresult = (LocalBufferLookupEnt *)
     396       14022 :                 hash_search(LocalBufHash, (void *) &bufHdr->tag,
     397             :                             HASH_REMOVE, NULL);
     398       14022 :             if (!hresult)       /* shouldn't happen */
     399           0 :                 elog(ERROR, "local buffer hash table corrupted");
     400             :             /* Mark buffer invalid */
     401       14022 :             CLEAR_BUFFERTAG(bufHdr->tag);
     402       14022 :             buf_state &= ~BUF_FLAG_MASK;
     403       14022 :             buf_state &= ~BUF_USAGECOUNT_MASK;
     404       14022 :             pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
     405             :         }
     406             :     }
     407        3196 : }
     408             : 
     409             : /*
     410             :  * InitLocalBuffers -
     411             :  *    init the local buffer cache. Since most queries (esp. multi-user ones)
     412             :  *    don't involve local buffers, we delay allocating actual memory for the
     413             :  *    buffers until we need them; just make the buffer headers here.
     414             :  */
     415             : static void
     416         264 : InitLocalBuffers(void)
     417             : {
     418         264 :     int         nbufs = num_temp_buffers;
     419             :     HASHCTL     info;
     420             :     int         i;
     421             : 
     422             :     /*
     423             :      * Parallel workers can't access data in temporary tables, because they
     424             :      * have no visibility into the local buffers of their leader.  This is a
     425             :      * convenient, low-cost place to provide a backstop check for that.  Note
     426             :      * that we don't wish to prevent a parallel worker from accessing catalog
     427             :      * metadata about a temp table, so checks at higher levels would be
     428             :      * inappropriate.
     429             :      */
     430         264 :     if (IsParallelWorker())
     431           0 :         ereport(ERROR,
     432             :                 (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
     433             :                  errmsg("cannot access temporary tables during a parallel operation")));
     434             : 
     435             :     /* Allocate and zero buffer headers and auxiliary arrays */
     436         264 :     LocalBufferDescriptors = (BufferDesc *) calloc(nbufs, sizeof(BufferDesc));
     437         264 :     LocalBufferBlockPointers = (Block *) calloc(nbufs, sizeof(Block));
     438         264 :     LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
     439         264 :     if (!LocalBufferDescriptors || !LocalBufferBlockPointers || !LocalRefCount)
     440           0 :         ereport(FATAL,
     441             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     442             :                  errmsg("out of memory")));
     443             : 
     444         264 :     nextFreeLocalBuf = 0;
     445             : 
     446             :     /* initialize fields that need to start off nonzero */
     447      270600 :     for (i = 0; i < nbufs; i++)
     448             :     {
     449      270336 :         BufferDesc *buf = GetLocalBufferDescriptor(i);
     450             : 
     451             :         /*
     452             :          * negative to indicate local buffer. This is tricky: shared buffers
     453             :          * start with 0. We have to start with -2. (Note that the routine
     454             :          * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
     455             :          * is -1.)
     456             :          */
     457      270336 :         buf->buf_id = -i - 2;
     458             : 
     459             :         /*
     460             :          * Intentionally do not initialize the buffer's atomic variable
     461             :          * (besides zeroing the underlying memory above). That way we get
     462             :          * errors on platforms without atomics, if somebody (re-)introduces
     463             :          * atomic operations for local buffers.
     464             :          */
     465             :     }
     466             : 
     467             :     /* Create the lookup hash table */
     468        3696 :     MemSet(&info, 0, sizeof(info));
     469         264 :     info.keysize = sizeof(BufferTag);
     470         264 :     info.entrysize = sizeof(LocalBufferLookupEnt);
     471             : 
     472         264 :     LocalBufHash = hash_create("Local Buffer Lookup Table",
     473             :                                nbufs,
     474             :                                &info,
     475             :                                HASH_ELEM | HASH_BLOBS);
     476             : 
     477         264 :     if (!LocalBufHash)
     478           0 :         elog(ERROR, "could not initialize local buffer hash table");
     479             : 
     480             :     /* Initialization done, mark buffers allocated */
     481         264 :     NLocBuffer = nbufs;
     482         264 : }
     483             : 
     484             : /*
     485             :  * GetLocalBufferStorage - allocate memory for a local buffer
     486             :  *
     487             :  * The idea of this function is to aggregate our requests for storage
     488             :  * so that the memory manager doesn't see a whole lot of relatively small
     489             :  * requests.  Since we'll never give back a local buffer once it's created
     490             :  * within a particular process, no point in burdening memmgr with separately
     491             :  * managed chunks.
     492             :  */
     493             : static Block
     494       13014 : GetLocalBufferStorage(void)
     495             : {
     496             :     static char *cur_block = NULL;
     497             :     static int  next_buf_in_block = 0;
     498             :     static int  num_bufs_in_block = 0;
     499             :     static int  total_bufs_allocated = 0;
     500             :     static MemoryContext LocalBufferContext = NULL;
     501             : 
     502             :     char       *this_buf;
     503             : 
     504             :     Assert(total_bufs_allocated < NLocBuffer);
     505             : 
     506       13014 :     if (next_buf_in_block >= num_bufs_in_block)
     507             :     {
     508             :         /* Need to make a new request to memmgr */
     509             :         int         num_bufs;
     510             : 
     511             :         /*
     512             :          * We allocate local buffers in a context of their own, so that the
     513             :          * space eaten for them is easily recognizable in MemoryContextStats
     514             :          * output.  Create the context on first use.
     515             :          */
     516         396 :         if (LocalBufferContext == NULL)
     517         264 :             LocalBufferContext =
     518         264 :                 AllocSetContextCreate(TopMemoryContext,
     519             :                                       "LocalBufferContext",
     520             :                                       ALLOCSET_DEFAULT_SIZES);
     521             : 
     522             :         /* Start with a 16-buffer request; subsequent ones double each time */
     523         396 :         num_bufs = Max(num_bufs_in_block * 2, 16);
     524             :         /* But not more than what we need for all remaining local bufs */
     525         396 :         num_bufs = Min(num_bufs, NLocBuffer - total_bufs_allocated);
     526             :         /* And don't overflow MaxAllocSize, either */
     527         396 :         num_bufs = Min(num_bufs, MaxAllocSize / BLCKSZ);
     528             : 
     529         792 :         cur_block = (char *) MemoryContextAlloc(LocalBufferContext,
     530         396 :                                                 num_bufs * BLCKSZ);
     531         396 :         next_buf_in_block = 0;
     532         396 :         num_bufs_in_block = num_bufs;
     533             :     }
     534             : 
     535             :     /* Allocate next buffer in current memory block */
     536       13014 :     this_buf = cur_block + next_buf_in_block * BLCKSZ;
     537       13014 :     next_buf_in_block++;
     538       13014 :     total_bufs_allocated++;
     539             : 
     540       13014 :     return (Block) this_buf;
     541             : }
     542             : 
     543             : /*
     544             :  * CheckForLocalBufferLeaks - ensure this backend holds no local buffer pins
     545             :  *
     546             :  * This is just like CheckForBufferLeaks(), but for local buffers.
     547             :  */
     548             : static void
     549      507906 : CheckForLocalBufferLeaks(void)
     550             : {
     551             : #ifdef USE_ASSERT_CHECKING
     552             :     if (LocalRefCount)
     553             :     {
     554             :         int         RefCountErrors = 0;
     555             :         int         i;
     556             : 
     557             :         for (i = 0; i < NLocBuffer; i++)
     558             :         {
     559             :             if (LocalRefCount[i] != 0)
     560             :             {
     561             :                 Buffer      b = -i - 1;
     562             : 
     563             :                 PrintBufferLeakWarning(b);
     564             :                 RefCountErrors++;
     565             :             }
     566             :         }
     567             :         Assert(RefCountErrors == 0);
     568             :     }
     569             : #endif
     570      507906 : }
     571             : 
     572             : /*
     573             :  * AtEOXact_LocalBuffers - clean up at end of transaction.
     574             :  *
     575             :  * This is just like AtEOXact_Buffers, but for local buffers.
     576             :  */
     577             : void
     578      494820 : AtEOXact_LocalBuffers(bool isCommit)
     579             : {
     580      494820 :     CheckForLocalBufferLeaks();
     581      494820 : }
     582             : 
     583             : /*
     584             :  * AtProcExit_LocalBuffers - ensure we have dropped pins during backend exit.
     585             :  *
     586             :  * This is just like AtProcExit_Buffers, but for local buffers.
     587             :  */
     588             : void
     589       13086 : AtProcExit_LocalBuffers(void)
     590             : {
     591             :     /*
     592             :      * We shouldn't be holding any remaining pins; if we are, and assertions
     593             :      * aren't enabled, we'll fail later in DropRelFileNodeBuffers while trying
     594             :      * to drop the temp rels.
     595             :      */
     596       13086 :     CheckForLocalBufferLeaks();
     597       13086 : }

Generated by: LCOV version 1.13