]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add alignment option to ShmemRequestStruct()
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 5 Apr 2026 23:13:06 +0000 (02:13 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 5 Apr 2026 23:13:06 +0000 (02:13 +0300)
The buffer blocks, converted to use ShmemRequestStruct() in the next
commit, are IO-aligned. This might come handy in other places too, so
make it an explicit feature of ShmemRequestStruct().

Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://www.postgresql.org/message-id/CAExHW5vM1bneLYfg0wGeAa=52UiJ3z4vKd3AJ72X8Fw6k3KKrg@mail.gmail.com

src/backend/storage/ipc/shmem.c
src/include/storage/shmem.h

index e60dfb4272c36efff779c8bc6df016ad60d62534..92c96257588f484d6faa720d48a4d581dd94a08e 100644 (file)
 #include "fmgr.h"
 #include "funcapi.h"
 #include "miscadmin.h"
+#include "port/pg_bitutils.h"
 #include "port/pg_numa.h"
 #include "storage/lwlock.h"
 #include "storage/pg_shmem.h"
@@ -235,7 +236,7 @@ typedef struct ShmemAllocatorData
 
 #define ShmemIndexLock (&ShmemAllocator->index_lock)
 
-static void *ShmemAllocRaw(Size size, Size *allocated_size);
+static void *ShmemAllocRaw(Size size, Size alignment, Size *allocated_size);
 
 /* shared memory global variables */
 
@@ -336,6 +337,7 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
 {
        ShmemRequest *request;
 
+       /* Check the options */
        if (options->name == NULL)
                elog(ERROR, "shared memory request is missing 'name' option");
 
@@ -354,6 +356,11 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
                                 options->size, options->name);
        }
 
+       if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
+               elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
+                        options->alignment, options->name);
+
+       /* Check that we're in the right state */
        if (shmem_request_state != SRS_REQUESTING)
                elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
 
@@ -393,9 +400,14 @@ ShmemGetRequestedSize(void)
        /* memory needed for all the requested areas */
        foreach_ptr(ShmemRequest, request, pending_shmem_requests)
        {
+               size_t          alignment = request->options->alignment;
+
+               /* pad the start address for alignment like ShmemAllocRaw() does */
+               if (alignment < PG_CACHE_LINE_SIZE)
+                       alignment = PG_CACHE_LINE_SIZE;
+               size = TYPEALIGN(alignment, size);
+
                size = add_size(size, request->options->size);
-               /* calculate alignment padding like ShmemAllocRaw() does */
-               size = CACHELINEALIGN(size);
        }
 
        return size;
@@ -520,7 +532,9 @@ InitShmemIndexEntry(ShmemRequest *request)
         * We inserted the entry to the shared memory index.  Allocate requested
         * amount of shared memory for it, and initialize the index entry.
         */
-       structPtr = ShmemAllocRaw(request->options->size, &allocated_size);
+       structPtr = ShmemAllocRaw(request->options->size,
+                                                         request->options->alignment,
+                                                         &allocated_size);
        if (structPtr == NULL)
        {
                /* out of memory; remove the failed ShmemIndex entry */
@@ -749,7 +763,7 @@ ShmemAlloc(Size size)
        void       *newSpace;
        Size            allocated_size;
 
-       newSpace = ShmemAllocRaw(size, &allocated_size);
+       newSpace = ShmemAllocRaw(size, 0, &allocated_size);
        if (!newSpace)
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
@@ -768,7 +782,7 @@ ShmemAllocNoError(Size size)
 {
        Size            allocated_size;
 
-       return ShmemAllocRaw(size, &allocated_size);
+       return ShmemAllocRaw(size, 0, &allocated_size);
 }
 
 /*
@@ -778,8 +792,9 @@ ShmemAllocNoError(Size size)
  * be equal to the number requested plus any padding we choose to add.
  */
 static void *
-ShmemAllocRaw(Size size, Size *allocated_size)
+ShmemAllocRaw(Size size, Size alignment, Size *allocated_size)
 {
+       Size            rawStart;
        Size            newStart;
        Size            newFree;
        void       *newSpace;
@@ -795,14 +810,15 @@ ShmemAllocRaw(Size size, Size *allocated_size)
         * structures out to a power-of-two size - but without this, even that
         * won't be sufficient.
         */
-       size = CACHELINEALIGN(size);
-       *allocated_size = size;
+       if (alignment < PG_CACHE_LINE_SIZE)
+               alignment = PG_CACHE_LINE_SIZE;
 
        Assert(ShmemSegHdr != NULL);
 
        SpinLockAcquire(&ShmemAllocator->shmem_lock);
 
-       newStart = ShmemAllocator->free_offset;
+       rawStart = ShmemAllocator->free_offset;
+       newStart = TYPEALIGN(alignment, rawStart);
 
        newFree = newStart + size;
        if (newFree <= ShmemSegHdr->totalsize)
@@ -816,8 +832,9 @@ ShmemAllocRaw(Size size, Size *allocated_size)
        SpinLockRelease(&ShmemAllocator->shmem_lock);
 
        /* note this assert is okay with newSpace == NULL */
-       Assert(newSpace == (void *) CACHELINEALIGN(newSpace));
+       Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace));
 
+       *allocated_size = newFree - rawStart;
        return newSpace;
 }
 
index 1680712498f0f95c913b2ed606d29473d8510aa6..af7fe893bc4b3cb70a2f03386b27145aa796927e 100644 (file)
@@ -51,6 +51,12 @@ typedef struct ShmemStructOpts
         */
        ssize_t         size;
 
+       /*
+        * Alignment of the starting address. If not set, defaults to cacheline
+        * boundary.  Must be a power of two.
+        */
+       size_t          alignment;
+
        /*
         * When the shmem area is initialized or attached to, pointer to it is
         * stored in *ptr.  It usually points to a global variable, used to access