LCOV - code coverage report
Current view: top level - src/include/utils - memutils_memorychunk.h (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 100.0 % 14 14
Test Date: 2026-03-03 14:15:12 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * memutils_memorychunk.h
       4              :  *    Here we define a struct named MemoryChunk which implementations of
       5              :  *    MemoryContexts may use as a header for chunks of memory they allocate.
       6              :  *
       7              :  * MemoryChunk provides a lightweight header that a MemoryContext can use to
       8              :  * store a reference back to the block which the given chunk is allocated on
       9              :  * and also an additional 30-bits to store another value such as the size of
      10              :  * the allocated chunk.
      11              :  *
      12              :  * Although MemoryChunks are used by each of our MemoryContexts, future
      13              :  * implementations may choose to implement their own method for storing chunk
      14              :  * headers.  The only requirement is that the header ends with an 8-byte value
      15              :  * which the least significant 4-bits of are set to the MemoryContextMethodID
      16              :  * of the given context.
      17              :  *
      18              :  * By default, a MemoryChunk is 8 bytes in size, however, when
      19              :  * MEMORY_CONTEXT_CHECKING is defined the header becomes 16 bytes in size due
      20              :  * to the additional requested_size field.  The MemoryContext may use this
      21              :  * field for whatever they wish, but it is intended to be used for additional
      22              :  * checks which are only done in MEMORY_CONTEXT_CHECKING builds.
      23              :  *
      24              :  * The MemoryChunk contains a uint64 field named 'hdrmask'.  This field is
      25              :  * used to encode 4 separate pieces of information.  Starting with the least
      26              :  * significant bits of 'hdrmask', the bit space is reserved as follows:
      27              :  *
      28              :  * 1.   4-bits to indicate the MemoryContextMethodID as defined by
      29              :  *      MEMORY_CONTEXT_METHODID_MASK
      30              :  * 2.   1-bit to denote an "external" chunk (see below)
      31              :  * 3.   30-bits reserved for the MemoryContext to use for anything it
      32              :  *      requires.  Most MemoryContexts likely want to store the size of the
      33              :  *      chunk here.
      34              :  * 4.   30-bits for the number of bytes that must be subtracted from the chunk
      35              :  *      to obtain the address of the block that the chunk is stored on.
      36              :  *
      37              :  * If you're paying close attention, you'll notice this adds up to 65 bits
      38              :  * rather than 64 bits.  This is because the highest-order bit of #3 is the
      39              :  * same bit as the lowest-order bit of #4.  We can do this as we insist that
      40              :  * the chunk and block pointers are both MAXALIGNed, therefore the relative
      41              :  * offset between those will always be a MAXALIGNed value which means the
      42              :  * lowest order bit is always 0.  When fetching the chunk to block offset we
      43              :  * mask out the lowest-order bit to ensure it's still zero.
      44              :  *
      45              :  * In some cases, for example when memory allocations become large, it's
      46              :  * possible fields 3 and 4 above are not large enough to store the values
      47              :  * required for the chunk.  In this case, the MemoryContext can choose to mark
      48              :  * the chunk as "external" by calling the MemoryChunkSetHdrMaskExternal()
      49              :  * function.  When this is done, fields 3 and 4 are unavailable for use by the
      50              :  * MemoryContext and it's up to the MemoryContext itself to devise its own
      51              :  * method for getting the reference to the block.
      52              :  *
      53              :  * Interface:
      54              :  *
      55              :  * MemoryChunkSetHdrMask:
      56              :  *      Used to set up a non-external MemoryChunk.
      57              :  *
      58              :  * MemoryChunkSetHdrMaskExternal:
      59              :  *      Used to set up an externally managed MemoryChunk.
      60              :  *
      61              :  * MemoryChunkIsExternal:
      62              :  *      Determine if the given MemoryChunk is externally managed, i.e.
      63              :  *      MemoryChunkSetHdrMaskExternal() was called on the chunk.
      64              :  *
      65              :  * MemoryChunkGetValue:
      66              :  *      For non-external chunks, return the stored 30-bit value as it was set
      67              :  *      in the call to MemoryChunkSetHdrMask().
      68              :  *
      69              :  * MemoryChunkGetBlock:
      70              :  *      For non-external chunks, return a pointer to the block as it was set
      71              :  *      in the call to MemoryChunkSetHdrMask().
      72              :  *
      73              :  * Also exports:
      74              :  *      MEMORYCHUNK_MAX_VALUE
      75              :  *      MEMORYCHUNK_MAX_BLOCKOFFSET
      76              :  *      PointerGetMemoryChunk
      77              :  *      MemoryChunkGetPointer
      78              :  *
      79              :  * Portions Copyright (c) 2022-2026, PostgreSQL Global Development Group
      80              :  * Portions Copyright (c) 1994, Regents of the University of California
      81              :  *
      82              :  * src/include/utils/memutils_memorychunk.h
      83              :  *
      84              :  *-------------------------------------------------------------------------
      85              :  */
      86              : 
      87              : #ifndef MEMUTILS_MEMORYCHUNK_H
      88              : #define MEMUTILS_MEMORYCHUNK_H
      89              : 
      90              : #include "utils/memutils_internal.h"
      91              : 
      92              :  /*
      93              :   * The maximum allowed value that MemoryContexts can store in the value
      94              :   * field.  Must be 1 less than a power of 2.
      95              :   */
      96              : #define MEMORYCHUNK_MAX_VALUE           UINT64CONST(0x3FFFFFFF)
      97              : 
      98              : /*
      99              :  * The maximum distance in bytes that a MemoryChunk can be offset from the
     100              :  * block that is storing the chunk.  Must be 1 less than a power of 2.
     101              :  */
     102              : #define MEMORYCHUNK_MAX_BLOCKOFFSET     UINT64CONST(0x3FFFFFFF)
     103              : 
     104              : /*
     105              :  * As above, but mask out the lowest-order (always zero) bit as this is shared
     106              :  * with the MemoryChunkGetValue field.
     107              :  */
     108              : #define MEMORYCHUNK_BLOCKOFFSET_MASK    UINT64CONST(0x3FFFFFFE)
     109              : 
     110              : /* define the least significant base-0 bit of each portion of the hdrmask */
     111              : #define MEMORYCHUNK_EXTERNAL_BASEBIT    MEMORY_CONTEXT_METHODID_BITS
     112              : #define MEMORYCHUNK_VALUE_BASEBIT       (MEMORYCHUNK_EXTERNAL_BASEBIT + 1)
     113              : #define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 29)
     114              : 
     115              : /*
     116              :  * A magic number for storing in the free bits of an external chunk.  This
     117              :  * must mask out the bits used for storing the MemoryContextMethodID and the
     118              :  * external bit.
     119              :  */
     120              : #define MEMORYCHUNK_MAGIC       (UINT64CONST(0xB1A8DB858EB6EFBA) >> \
     121              :                                  MEMORYCHUNK_VALUE_BASEBIT << \
     122              :                                  MEMORYCHUNK_VALUE_BASEBIT)
     123              : 
     124              : typedef struct MemoryChunk
     125              : {
     126              : #ifdef MEMORY_CONTEXT_CHECKING
     127              :     Size        requested_size;
     128              : #endif
     129              : 
     130              :     /* bitfield for storing details about the chunk */
     131              :     uint64      hdrmask;        /* must be last */
     132              : } MemoryChunk;
     133              : 
     134              : /* Get the MemoryChunk from the pointer */
     135              : #define PointerGetMemoryChunk(p) \
     136              :     ((MemoryChunk *) ((char *) (p) - sizeof(MemoryChunk)))
     137              : /* Get the pointer from the MemoryChunk */
     138              : #define MemoryChunkGetPointer(c) \
     139              :     ((void *) ((char *) (c) + sizeof(MemoryChunk)))
     140              : 
     141              : /* private macros for making the inline functions below more simple */
     142              : #define HdrMaskIsExternal(hdrmask) \
     143              :     ((hdrmask) & (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT))
     144              : #define HdrMaskGetValue(hdrmask) \
     145              :     (((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE)
     146              : 
     147              : /*
     148              :  * Shift the block offset down to the 0th bit position and mask off the single
     149              :  * bit that's shared with the MemoryChunkGetValue field.
     150              :  */
     151              : #define HdrMaskBlockOffset(hdrmask) \
     152              :     (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_BLOCKOFFSET_MASK)
     153              : 
     154              : /* For external chunks only, check the magic number matches */
     155              : #define HdrMaskCheckMagic(hdrmask) \
     156              :     (MEMORYCHUNK_MAGIC == \
     157              :      ((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT << MEMORYCHUNK_VALUE_BASEBIT))
     158              : /*
     159              :  * MemoryChunkSetHdrMask
     160              :  *      Store the given 'block', 'chunk_size' and 'methodid' in the given
     161              :  *      MemoryChunk.
     162              :  *
     163              :  * The number of bytes between 'block' and 'chunk' must be <=
     164              :  * MEMORYCHUNK_MAX_BLOCKOFFSET.
     165              :  * 'value' must be <= MEMORYCHUNK_MAX_VALUE.
     166              :  * Both 'chunk' and 'block' must be MAXALIGNed pointers.
     167              :  */
     168              : static inline void
     169    540281217 : MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
     170              :                       Size value, MemoryContextMethodID methodid)
     171              : {
     172    540281217 :     Size        blockoffset = (char *) chunk - (char *) block;
     173              : 
     174              :     Assert((char *) chunk >= (char *) block);
     175              :     Assert((blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK) == blockoffset);
     176              :     Assert(value <= MEMORYCHUNK_MAX_VALUE);
     177              :     Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
     178              : 
     179    540281217 :     chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) |
     180    540281217 :         (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) |
     181              :         methodid;
     182    540281217 : }
     183              : 
     184              : /*
     185              :  * MemoryChunkSetHdrMaskExternal
     186              :  *      Set 'chunk' as an externally managed chunk.  Here we only record the
     187              :  *      MemoryContextMethodID and set the external chunk bit.
     188              :  */
     189              : static inline void
     190     11134079 : MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk,
     191              :                               MemoryContextMethodID methodid)
     192              : {
     193              :     Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
     194              : 
     195     11134079 :     chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) |
     196              :         methodid;
     197     11134079 : }
     198              : 
     199              : /*
     200              :  * MemoryChunkIsExternal
     201              :  *      Return true if 'chunk' is marked as external.
     202              :  */
     203              : static inline bool
     204    296819625 : MemoryChunkIsExternal(MemoryChunk *chunk)
     205              : {
     206              :     /*
     207              :      * External chunks should always store MEMORYCHUNK_MAGIC in the upper
     208              :      * portion of the hdrmask, check that nothing has stomped on that.
     209              :      */
     210              :     Assert(!HdrMaskIsExternal(chunk->hdrmask) ||
     211              :            HdrMaskCheckMagic(chunk->hdrmask));
     212              : 
     213    296819625 :     return HdrMaskIsExternal(chunk->hdrmask);
     214              : }
     215              : 
     216              : /*
     217              :  * MemoryChunkGetValue
     218              :  *      For non-external chunks, returns the value field as it was set in
     219              :  *      MemoryChunkSetHdrMask.
     220              :  */
     221              : static inline Size
     222    277863608 : MemoryChunkGetValue(MemoryChunk *chunk)
     223              : {
     224              :     Assert(!HdrMaskIsExternal(chunk->hdrmask));
     225              : 
     226    277863608 :     return HdrMaskGetValue(chunk->hdrmask);
     227              : }
     228              : 
     229              : /*
     230              :  * MemoryChunkGetBlock
     231              :  *      For non-external chunks, returns the pointer to the block as was set
     232              :  *      in MemoryChunkSetHdrMask.
     233              :  */
     234              : static inline void *
     235    267499649 : MemoryChunkGetBlock(MemoryChunk *chunk)
     236              : {
     237              :     Assert(!HdrMaskIsExternal(chunk->hdrmask));
     238              : 
     239    267499649 :     return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask));
     240              : }
     241              : 
     242              : /* cleanup all internal definitions */
     243              : #undef MEMORYCHUNK_BLOCKOFFSET_MASK
     244              : #undef MEMORYCHUNK_EXTERNAL_BASEBIT
     245              : #undef MEMORYCHUNK_VALUE_BASEBIT
     246              : #undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT
     247              : #undef MEMORYCHUNK_MAGIC
     248              : #undef HdrMaskIsExternal
     249              : #undef HdrMaskGetValue
     250              : #undef HdrMaskBlockOffset
     251              : #undef HdrMaskCheckMagic
     252              : 
     253              : #endif                          /* MEMUTILS_MEMORYCHUNK_H */
        

Generated by: LCOV version 2.0-1