LCOV - code coverage report
Current view: top level - src/backend/storage/buffer - buf_table.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.5 % 22 21
Test Date: 2026-04-07 14:16:30 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * buf_table.c
       4              :  *    routines for mapping BufferTags to buffer indexes.
       5              :  *
       6              :  * Note: the routines in this file do no locking of their own.  The caller
       7              :  * must hold a suitable lock on the appropriate BufMappingLock, as specified
       8              :  * in the comments.  We can't do the locking inside these functions because
       9              :  * in most cases the caller needs to adjust the buffer header contents
      10              :  * before the lock is released (see notes in README).
      11              :  *
      12              :  *
      13              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      14              :  * Portions Copyright (c) 1994, Regents of the University of California
      15              :  *
      16              :  *
      17              :  * IDENTIFICATION
      18              :  *    src/backend/storage/buffer/buf_table.c
      19              :  *
      20              :  *-------------------------------------------------------------------------
      21              :  */
      22              : #include "postgres.h"
      23              : 
      24              : #include "storage/buf_internals.h"
      25              : #include "storage/subsystems.h"
      26              : 
      27              : /* entry for buffer lookup hashtable */
      28              : typedef struct
      29              : {
      30              :     BufferTag   key;            /* Tag of a disk page */
      31              :     int         id;             /* Associated buffer ID */
      32              : } BufferLookupEnt;
      33              : 
      34              : static HTAB *SharedBufHash;
      35              : 
      36              : static void BufTableShmemRequest(void *arg);
      37              : 
      38              : const ShmemCallbacks BufTableShmemCallbacks = {
      39              :     .request_fn = BufTableShmemRequest,
      40              :     /* no special initialization needed, the hash table will start empty */
      41              : };
      42              : 
      43              : /*
      44              :  * Register shmem hash table for mapping buffers.
      45              :  *      size is the desired hash table size (possibly more than NBuffers)
      46              :  */
      47              : void
      48         1234 : BufTableShmemRequest(void *arg)
      49              : {
      50              :     int         size;
      51              : 
      52              :     /*
      53              :      * Request the shared buffer lookup hashtable.
      54              :      *
      55              :      * Since we can't tolerate running out of lookup table entries, we must be
      56              :      * sure to specify an adequate table size here.  The maximum steady-state
      57              :      * usage is of course NBuffers entries, but BufferAlloc() tries to insert
      58              :      * a new entry before deleting the old.  In principle this could be
      59              :      * happening in each partition concurrently, so we could need as many as
      60              :      * NBuffers + NUM_BUFFER_PARTITIONS entries.
      61              :      */
      62         1234 :     size = NBuffers + NUM_BUFFER_PARTITIONS;
      63              : 
      64         1234 :     ShmemRequestHash(.name = "Shared Buffer Lookup Table",
      65              :                      .nelems = size,
      66              :                      .ptr = &SharedBufHash,
      67              :                      .hash_info.keysize = sizeof(BufferTag),
      68              :                      .hash_info.entrysize = sizeof(BufferLookupEnt),
      69              :                      .hash_info.num_partitions = NUM_BUFFER_PARTITIONS,
      70              :                      .hash_flags = HASH_ELEM | HASH_BLOBS | HASH_PARTITION | HASH_FIXED_SIZE,
      71              :         );
      72         1234 : }
      73              : 
      74              : /*
      75              :  * BufTableHashCode
      76              :  *      Compute the hash code associated with a BufferTag
      77              :  *
      78              :  * This must be passed to the lookup/insert/delete routines along with the
      79              :  * tag.  We do it like this because the callers need to know the hash code
      80              :  * in order to determine which buffer partition to lock, and we don't want
      81              :  * to do the hash computation twice (hash_any is a bit slow).
      82              :  */
      83              : uint32
      84     84975002 : BufTableHashCode(BufferTag *tagPtr)
      85              : {
      86     84975002 :     return get_hash_value(SharedBufHash, tagPtr);
      87              : }
      88              : 
      89              : /*
      90              :  * BufTableLookup
      91              :  *      Lookup the given BufferTag; return buffer ID, or -1 if not found
      92              :  *
      93              :  * Caller must hold at least share lock on BufMappingLock for tag's partition
      94              :  */
      95              : int
      96     83148310 : BufTableLookup(BufferTag *tagPtr, uint32 hashcode)
      97              : {
      98              :     BufferLookupEnt *result;
      99              : 
     100              :     result = (BufferLookupEnt *)
     101     83148310 :         hash_search_with_hash_value(SharedBufHash,
     102              :                                     tagPtr,
     103              :                                     hashcode,
     104              :                                     HASH_FIND,
     105              :                                     NULL);
     106              : 
     107     83148310 :     if (!result)
     108      1987646 :         return -1;
     109              : 
     110     81160664 :     return result->id;
     111              : }
     112              : 
     113              : /*
     114              :  * BufTableInsert
     115              :  *      Insert a hashtable entry for given tag and buffer ID,
     116              :  *      unless an entry already exists for that tag
     117              :  *
     118              :  * Returns -1 on successful insertion.  If a conflicting entry exists
     119              :  * already, returns the buffer ID in that entry.
     120              :  *
     121              :  * Caller must hold exclusive lock on BufMappingLock for tag's partition
     122              :  */
     123              : int
     124      2259669 : BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id)
     125              : {
     126              :     BufferLookupEnt *result;
     127              :     bool        found;
     128              : 
     129              :     Assert(buf_id >= 0);     /* -1 is reserved for not-in-table */
     130              :     Assert(tagPtr->blockNum != P_NEW);   /* invalid tag */
     131              : 
     132              :     result = (BufferLookupEnt *)
     133      2259669 :         hash_search_with_hash_value(SharedBufHash,
     134              :                                     tagPtr,
     135              :                                     hashcode,
     136              :                                     HASH_ENTER,
     137              :                                     &found);
     138              : 
     139      2259669 :     if (found)                  /* found something already in the table */
     140         1024 :         return result->id;
     141              : 
     142      2258645 :     result->id = buf_id;
     143              : 
     144      2258645 :     return -1;
     145              : }
     146              : 
     147              : /*
     148              :  * BufTableDelete
     149              :  *      Delete the hashtable entry for given tag (which must exist)
     150              :  *
     151              :  * Caller must hold exclusive lock on BufMappingLock for tag's partition
     152              :  */
     153              : void
     154      1544502 : BufTableDelete(BufferTag *tagPtr, uint32 hashcode)
     155              : {
     156              :     BufferLookupEnt *result;
     157              : 
     158              :     result = (BufferLookupEnt *)
     159      1544502 :         hash_search_with_hash_value(SharedBufHash,
     160              :                                     tagPtr,
     161              :                                     hashcode,
     162              :                                     HASH_REMOVE,
     163              :                                     NULL);
     164              : 
     165      1544502 :     if (!result)                /* shouldn't happen */
     166            0 :         elog(ERROR, "shared buffer hash table corrupted");
     167      1544502 : }
        

Generated by: LCOV version 2.0-1