PostgreSQL Source Code git master
Loading...
Searching...
No Matches
shmem.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/slru.h"
#include "common/int.h"
#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"
#include "storage/shmem.h"
#include "storage/shmem_internal.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/tuplestore.h"
Include dependency graph for shmem.c:

Go to the source code of this file.

Data Structures

struct  ShmemRequest
 
struct  ShmemAllocatorData
 
struct  ShmemIndexEnt
 

Macros

#define ShmemIndexLock   (&ShmemAllocator->index_lock)
 
#define SHMEM_INDEX_KEYSIZE   (48)
 
#define SHMEM_INDEX_ADDITIONAL_SIZE   (128)
 
#define PG_GET_SHMEM_SIZES_COLS   4
 
#define PG_GET_SHMEM_NUMA_SIZES_COLS   3
 

Typedefs

typedef struct ShmemAllocatorData ShmemAllocatorData
 

Enumerations

enum  shmem_request_state {
  SRS_INITIAL , SRS_REQUESTING , SRS_INITIALIZING , SRS_ATTACHING ,
  SRS_AFTER_STARTUP_ATTACH_OR_INIT , SRS_DONE
}
 

Functions

static voidShmemAllocRaw (Size size, Size alignment, Size *allocated_size)
 
static void CallShmemCallbacksAfterStartup (const ShmemCallbacks *callbacks)
 
static void InitShmemIndexEntry (ShmemRequest *request)
 
static bool AttachShmemIndexEntry (ShmemRequest *request, bool missing_ok)
 
Datum pg_numa_available (PG_FUNCTION_ARGS)
 
void ShmemRequestStructWithOpts (const ShmemStructOpts *options)
 
void ShmemRequestInternal (ShmemStructOpts *options, ShmemRequestKind kind)
 
size_t ShmemGetRequestedSize (void)
 
void ShmemInitRequested (void)
 
void InitShmemAllocator (PGShmemHeader *seghdr)
 
void ResetShmemAllocator (void)
 
voidShmemAlloc (Size size)
 
voidShmemAllocNoError (Size size)
 
bool ShmemAddrIsValid (const void *addr)
 
void RegisterShmemCallbacks (const ShmemCallbacks *callbacks)
 
void ShmemCallRequestCallbacks (void)
 
voidShmemInitStruct (const char *name, Size size, bool *foundPtr)
 
Size add_size (Size s1, Size s2)
 
Size mul_size (Size s1, Size s2)
 
Datum pg_get_shmem_allocations (PG_FUNCTION_ARGS)
 
Datum pg_get_shmem_allocations_numa (PG_FUNCTION_ARGS)
 
Size pg_get_shmem_pagesize (void)
 

Variables

static Listregistered_shmem_callbacks
 
static Listpending_shmem_requests
 
static enum shmem_request_state shmem_request_state = SRS_INITIAL
 
static PGShmemHeaderShmemSegHdr
 
static voidShmemBase
 
static voidShmemEnd
 
static ShmemAllocatorDataShmemAllocator
 
static HTABShmemIndex
 
static bool firstNumaTouch = true
 

Macro Definition Documentation

◆ PG_GET_SHMEM_NUMA_SIZES_COLS

#define PG_GET_SHMEM_NUMA_SIZES_COLS   3

◆ PG_GET_SHMEM_SIZES_COLS

#define PG_GET_SHMEM_SIZES_COLS   4

◆ SHMEM_INDEX_ADDITIONAL_SIZE

#define SHMEM_INDEX_ADDITIONAL_SIZE   (128)

Definition at line 263 of file shmem.c.

◆ SHMEM_INDEX_KEYSIZE

#define SHMEM_INDEX_KEYSIZE   (48)

Definition at line 256 of file shmem.c.

◆ ShmemIndexLock

#define ShmemIndexLock   (&ShmemAllocator->index_lock)

Definition at line 237 of file shmem.c.

Typedef Documentation

◆ ShmemAllocatorData

Enumeration Type Documentation

◆ shmem_request_state

Enumerator
SRS_INITIAL 
SRS_REQUESTING 
SRS_INITIALIZING 
SRS_ATTACHING 
SRS_AFTER_STARTUP_ATTACH_OR_INIT 
SRS_DONE 

Definition at line 185 of file shmem.c.

186{
187 /* Initial state */
189
190 /*
191 * When we start calling the shmem_request callbacks, we enter the
192 * SRS_REQUESTING phase. All ShmemRequestStruct calls happen in this
193 * state.
194 */
196
197 /*
198 * Postmaster has finished all shmem requests, and is now initializing the
199 * shared memory segment. init_fn callbacks are called in this state.
200 */
202
203 /*
204 * A postmaster child process is starting up. attach_fn callbacks are
205 * called in this state.
206 */
208
209 /* An after-startup allocation or attachment is in progress */
211
212 /* Normal state after shmem initialization / attachment */
213 SRS_DONE,
214};
@ SRS_INITIALIZING
Definition shmem.c:201
@ SRS_DONE
Definition shmem.c:213
@ SRS_ATTACHING
Definition shmem.c:207
@ SRS_INITIAL
Definition shmem.c:188
@ SRS_AFTER_STARTUP_ATTACH_OR_INIT
Definition shmem.c:210
@ SRS_REQUESTING
Definition shmem.c:195

Function Documentation

◆ add_size()

Size add_size ( Size  s1,
Size  s2 
)

Definition at line 1048 of file shmem.c.

1049{
1050 Size result;
1051
1053 ereport(ERROR,
1055 errmsg("requested shared memory size overflows size_t")));
1056 return result;
1057}
size_t Size
Definition c.h:689
uint32 result
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
static bool pg_add_size_overflow(size_t a, size_t b, size_t *result)
Definition int.h:608
static char * errmsg
static int fb(int x)
char * s1
char * s2

References ereport, errcode(), errmsg, ERROR, fb(), pg_add_size_overflow(), result, s1, and s2.

Referenced by _brin_parallel_estimate_shared(), _bt_parallel_estimate_shared(), _gin_parallel_estimate_shared(), ApplyLauncherShmemRequest(), AsyncShmemRequest(), AutoVacuumShmemRequest(), BackgroundWorkerShmemRequest(), btestimateparallelscan(), BTreeShmemRequest(), CalculateFastPathLockShmemSize(), CalculateShmemSize(), CheckpointerShmemRequest(), CreateAnonymousSegment(), estimate_variable_size(), EstimateClientConnectionInfoSpace(), EstimateComboCIDStateSpace(), EstimateGUCStateSpace(), EstimateLibraryStateSpace(), EstimateParamExecSpace(), EstimateParamListSpace(), EstimateSnapshotSpace(), EstimateTransactionStateSpace(), ExecAggEstimate(), ExecAppendEstimate(), ExecBitmapHeapInstrumentEstimate(), ExecBitmapHeapInstrumentInitDSM(), ExecHashEstimate(), ExecIncrementalSortEstimate(), ExecIndexOnlyScanInstrumentEstimate(), ExecIndexOnlyScanInstrumentInitDSM(), ExecIndexScanInstrumentEstimate(), ExecIndexScanInstrumentInitDSM(), ExecMemoizeEstimate(), ExecSeqScanInstrumentEstimate(), ExecSeqScanInstrumentInitDSM(), ExecSortEstimate(), ExecTidRangeScanInstrumentEstimate(), ExecTidRangeScanInstrumentInitDSM(), expand_planner_arrays(), hash_estimate_size(), index_parallelscan_estimate(), index_parallelscan_initialize(), InitializeShmemGUCs(), MultiXactShmemRequest(), PMSignalShmemRequest(), PredicateLockShmemRequest(), ProcArrayShmemRequest(), ProcGlobalShmemRequest(), ProcSignalShmemRequest(), ReplicationOriginShmemRequest(), ReplicationSlotsShmemRequest(), RequestAddinShmemSpace(), SerializeTransactionState(), SharedInvalShmemRequest(), shm_toc_estimate(), ShmemGetRequestedSize(), StatsShmemSize(), table_parallelscan_estimate(), tuplesort_estimate_shared(), TwoPhaseShmemRequest(), WaitLSNShmemRequest(), WalSndShmemRequest(), and XLOGShmemRequest().

◆ AttachShmemIndexEntry()

static bool AttachShmemIndexEntry ( ShmemRequest request,
bool  missing_ok 
)
static

Definition at line 581 of file shmem.c.

582{
583 const char *name = request->options->name;
585
586 /* Look it up in the shmem index */
589 if (!index_entry)
590 {
591 if (!missing_ok)
593 (errmsg("could not find ShmemIndex entry for data structure \"%s\"",
594 request->options->name)));
595 return false;
596 }
597
598 /* Check that the size in the index matches the request */
599 if (index_entry->size != request->options->size &&
600 request->options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
601 {
603 (errmsg("shared memory struct \"%s\" was created with"
604 " different size: existing %zu, requested %zd",
605 name, index_entry->size, request->options->size)));
606 }
607
608 /*
609 * Re-establish the caller's pointer variable, or do other actions to
610 * attach depending on the kind of shmem area it is.
611 */
612 switch (request->kind)
613 {
615 if (request->options->ptr)
616 *(request->options->ptr) = index_entry->location;
617 break;
618 case SHMEM_KIND_HASH:
619 shmem_hash_attach(index_entry->location, request->options);
620 break;
621 case SHMEM_KIND_SLRU:
622 shmem_slru_attach(index_entry->location, request->options);
623 break;
624 }
625
626 return true;
627}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
@ HASH_FIND
Definition hsearch.h:108
static HTAB * ShmemIndex
Definition shmem.c:253
#define SHMEM_ATTACH_UNKNOWN_SIZE
Definition shmem.h:69
void shmem_hash_attach(void *location, ShmemStructOpts *base_options)
Definition shmem_hash.c:79
@ SHMEM_KIND_SLRU
@ SHMEM_KIND_HASH
@ SHMEM_KIND_STRUCT
void shmem_slru_attach(void *location, ShmemStructOpts *base_options)
Definition slru.c:359
const char * name

References ereport, errmsg, ERROR, fb(), HASH_FIND, hash_search(), name, SHMEM_ATTACH_UNKNOWN_SIZE, shmem_hash_attach(), SHMEM_KIND_HASH, SHMEM_KIND_SLRU, SHMEM_KIND_STRUCT, shmem_slru_attach(), and ShmemIndex.

Referenced by CallShmemCallbacksAfterStartup(), and ShmemInitStruct().

◆ CallShmemCallbacksAfterStartup()

static void CallShmemCallbacksAfterStartup ( const ShmemCallbacks callbacks)
static

Definition at line 899 of file shmem.c.

900{
901 bool found_any;
902 bool notfound_any;
903
906
907 /*
908 * Call the request callback first. The callback makes ShmemRequest*()
909 * calls for each shmem area, adding them to pending_shmem_requests.
910 */
912 if (callbacks->request_fn)
913 callbacks->request_fn(callbacks->opaque_arg);
915
917 {
919 return;
920 }
921
922 /* Hold ShmemIndexLock while we allocate all the shmem entries */
924
925 /*
926 * Check if the requested shared memory areas have already been
927 * initialized. We assume all the areas requested by the request callback
928 * to form a coherent unit such that they're all already initialized or
929 * none. Otherwise it would be ambiguous which callback, init or attach,
930 * to callback afterwards.
931 */
932 found_any = notfound_any = false;
934 {
935 if (hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL))
936 found_any = true;
937 else
938 notfound_any = true;
939 }
940 if (found_any && notfound_any)
941 elog(ERROR, "found some but not all");
942
943 /*
944 * Allocate or attach all the shmem areas requested by the request_fn
945 * callback.
946 */
948 {
949 if (found_any)
951 else
953
954 pfree(request->options);
955 }
958
959 /* Finish by calling the appropriate subsystem-specific callback */
960 if (found_any)
961 {
962 if (callbacks->attach_fn)
963 callbacks->attach_fn(callbacks->opaque_arg);
964 }
965 else
966 {
967 if (callbacks->init_fn)
968 callbacks->init_fn(callbacks->opaque_arg);
969 }
970
973}
#define Assert(condition)
Definition c.h:943
#define elog(elevel,...)
Definition elog.h:228
void list_free_deep(List *list)
Definition list.c:1560
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
void pfree(void *pointer)
Definition mcxt.c:1616
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
static void InitShmemIndexEntry(ShmemRequest *request)
Definition shmem.c:512
shmem_request_state
Definition shmem.c:186
static List * pending_shmem_requests
Definition shmem.c:170
#define ShmemIndexLock
Definition shmem.c:237
static bool AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok)
Definition shmem.c:581
ShmemRequestCallback request_fn
Definition shmem.h:133
ShmemInitCallback init_fn
Definition shmem.h:139
void * opaque_arg
Definition shmem.h:153
ShmemAttachCallback attach_fn
Definition shmem.h:147

References Assert, ShmemCallbacks::attach_fn, AttachShmemIndexEntry(), elog, ERROR, fb(), foreach_ptr, HASH_FIND, hash_search(), ShmemCallbacks::init_fn, InitShmemIndexEntry(), list_free_deep(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), NIL, ShmemCallbacks::opaque_arg, pending_shmem_requests, pfree(), ShmemCallbacks::request_fn, ShmemIndex, ShmemIndexLock, SRS_AFTER_STARTUP_ATTACH_OR_INIT, SRS_DONE, and SRS_REQUESTING.

Referenced by RegisterShmemCallbacks().

◆ InitShmemAllocator()

void InitShmemAllocator ( PGShmemHeader seghdr)

Definition at line 638 of file shmem.c.

639{
640 Size offset;
642 HASHCTL info;
643 int hash_flags;
644
645#ifndef EXEC_BACKEND
647#endif
648 Assert(seghdr != NULL);
649
651 {
653 }
654 else
655 {
658 }
659
660 /*
661 * We assume the pointer and offset are MAXALIGN. Not a hard requirement,
662 * but it's true today and keeps the math below simpler.
663 */
664 Assert(seghdr == (void *) MAXALIGN(seghdr));
665 Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset));
666
667 /*
668 * Allocations after this point should go through ShmemAlloc, which
669 * expects to allocate everything on cache line boundaries. Make sure the
670 * first allocation begins on a cache line boundary.
671 */
672 offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
673 if (offset > seghdr->totalsize)
676 errmsg("out of shared memory (%zu bytes requested)",
677 offset)));
678
679 /*
680 * In postmaster or stand-alone backend, initialize the shared memory
681 * allocator so that we can allocate shared memory for ShmemIndex using
682 * ShmemAlloc(). In a regular backend just set up the pointers required
683 * by ShmemAlloc().
684 */
685 ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
687 {
689 ShmemAllocator->free_offset = offset;
691 }
692
695 ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
696
697 /*
698 * Create (or attach to) the shared memory index of shmem areas.
699 *
700 * This is the same initialization as ShmemInitHash() does, but we cannot
701 * use ShmemInitHash() here because it relies on ShmemIndex being already
702 * initialized.
703 */
705
707 info.entrysize = sizeof(ShmemIndexEnt);
708 hash_flags = HASH_ELEM | HASH_STRINGS | HASH_FIXED_SIZE;
709
711 {
714 }
718 "ShmemIndex", hash_nelems,
719 &info, hash_flags);
721
722 /*
723 * Add an entry for ShmemIndex itself into ShmemIndex, so that it's
724 * visible in the pg_shmem_allocations view
725 */
727 {
728 bool found;
730 hash_search(ShmemIndex, "ShmemIndex", HASH_ENTER, &found);
731
732 Assert(!found);
734 result->allocated_size = ShmemAllocator->index_size;
735 result->location = ShmemAllocator->index;
736 }
737}
#define CACHELINEALIGN(LEN)
Definition c.h:899
#define MAXALIGN(LEN)
Definition c.h:896
int64_t int64
Definition c.h:621
Size hash_estimate_size(int64 num_entries, Size entrysize)
Definition dynahash.c:763
bool IsUnderPostmaster
Definition globals.c:122
#define HASH_STRINGS
Definition hsearch.h:91
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_FIXED_SIZE
Definition hsearch.h:100
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:670
static int list_length(const List *l)
Definition pg_list.h:152
static void * ShmemBase
Definition shmem.c:244
static void * ShmemEnd
Definition shmem.c:245
void * ShmemAlloc(Size size)
Definition shmem.c:764
static PGShmemHeader * ShmemSegHdr
Definition shmem.c:243
#define SHMEM_INDEX_ADDITIONAL_SIZE
Definition shmem.c:263
static ShmemAllocatorData * ShmemAllocator
Definition shmem.c:247
#define SHMEM_INDEX_KEYSIZE
Definition shmem.c:256
HTAB * shmem_hash_create(void *location, size_t size, bool found, const char *name, int64 nelems, HASHCTL *infoP, int hash_flags)
Definition shmem_hash.c:149
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
Size keysize
Definition hsearch.h:69
Size entrysize
Definition hsearch.h:70
Size totalsize
Definition pg_shmem.h:34
HASHHDR * index
Definition shmem.c:232
LWLock index_lock
Definition shmem.c:234
slock_t shmem_lock
Definition shmem.c:230
size_t index_size
Definition shmem.c:233

References Assert, CACHELINEALIGN, HASHCTL::entrysize, ereport, errcode(), errmsg, ERROR, fb(), ShmemAllocatorData::free_offset, HASH_ELEM, HASH_ENTER, hash_estimate_size(), HASH_FIXED_SIZE, hash_search(), HASH_STRINGS, ShmemAllocatorData::index, ShmemAllocatorData::index_lock, ShmemAllocatorData::index_size, IsUnderPostmaster, HASHCTL::keysize, list_length(), LWLockInitialize(), MAXALIGN, pending_shmem_requests, result, shmem_hash_create(), SHMEM_INDEX_ADDITIONAL_SIZE, SHMEM_INDEX_KEYSIZE, ShmemAllocatorData::shmem_lock, ShmemAlloc(), ShmemAllocator, ShmemBase, ShmemEnd, ShmemIndex, ShmemSegHdr, SpinLockInit(), SRS_INITIAL, SRS_INITIALIZING, SRS_REQUESTING, and PGShmemHeader::totalsize.

Referenced by CreateSharedMemoryAndSemaphores().

◆ InitShmemIndexEntry()

static void InitShmemIndexEntry ( ShmemRequest request)
static

Definition at line 512 of file shmem.c.

513{
514 const char *name = request->options->name;
516 bool found;
517 size_t allocated_size;
518 void *structPtr;
519
520 /* look it up in the shmem index */
523 if (found)
524 elog(ERROR, "shared memory struct \"%s\" is already initialized", name);
525 if (!index_entry)
526 {
527 /* tried to add it to the hash table, but there was no space */
530 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
531 name)));
532 }
533
534 /*
535 * We inserted the entry to the shared memory index. Allocate requested
536 * amount of shared memory for it, and initialize the index entry.
537 */
538 structPtr = ShmemAllocRaw(request->options->size,
539 request->options->alignment,
540 &allocated_size);
541 if (structPtr == NULL)
542 {
543 /* out of memory; remove the failed ShmemIndex entry */
547 errmsg("not enough shared memory for data structure"
548 " \"%s\" (%zd bytes requested)",
549 name, request->options->size)));
550 }
551 index_entry->size = request->options->size;
552 index_entry->allocated_size = allocated_size;
553 index_entry->location = structPtr;
554
555 /* Initialize depending on the kind of shmem area it is */
556 switch (request->kind)
557 {
559 if (request->options->ptr)
560 *(request->options->ptr) = index_entry->location;
561 break;
562 case SHMEM_KIND_HASH:
564 break;
565 case SHMEM_KIND_SLRU:
567 break;
568 }
569}
@ HASH_REMOVE
Definition hsearch.h:110
@ HASH_ENTER_NULL
Definition hsearch.h:111
static void * ShmemAllocRaw(Size size, Size alignment, Size *allocated_size)
Definition shmem.c:798
void shmem_hash_init(void *location, ShmemStructOpts *base_options)
Definition shmem_hash.c:63
void shmem_slru_init(void *location, ShmemStructOpts *base_options)
Definition slru.c:267

References elog, ereport, errcode(), errmsg, ERROR, fb(), HASH_ENTER_NULL, HASH_REMOVE, hash_search(), name, shmem_hash_init(), SHMEM_KIND_HASH, SHMEM_KIND_SLRU, SHMEM_KIND_STRUCT, shmem_slru_init(), ShmemAllocRaw(), and ShmemIndex.

Referenced by CallShmemCallbacksAfterStartup(), ShmemInitRequested(), and ShmemInitStruct().

◆ mul_size()

Size mul_size ( Size  s1,
Size  s2 
)

Definition at line 1063 of file shmem.c.

1064{
1065 Size result;
1066
1068 ereport(ERROR,
1070 errmsg("requested shared memory size overflows size_t")));
1071 return result;
1072}
static bool pg_mul_size_overflow(size_t a, size_t b, size_t *result)
Definition int.h:642

References ereport, errcode(), errmsg, ERROR, fb(), pg_mul_size_overflow(), result, s1, and s2.

Referenced by _brin_begin_parallel(), _bt_begin_parallel(), _gin_begin_parallel(), AioBackendShmemSize(), AioHandleDataShmemSize(), AioHandleIOVShmemSize(), AioHandleShmemSize(), ApplyLauncherShmemRequest(), AsyncShmemRequest(), AutoVacuumShmemRequest(), BackendStatusShmemAttach(), BackendStatusShmemRequest(), BackgroundWorkerShmemRequest(), BTreeShmemRequest(), CalculateFastPathLockShmemSize(), CheckpointerShmemRequest(), EstimateComboCIDStateSpace(), EstimatePendingSyncsSpace(), EstimateReindexStateSpace(), EstimateSnapshotSpace(), EstimateTransactionStateSpace(), ExecAggEstimate(), ExecBitmapHeapInstrumentEstimate(), ExecBitmapHeapInstrumentInitDSM(), ExecHashEstimate(), ExecIncrementalSortEstimate(), ExecIndexOnlyScanInstrumentEstimate(), ExecIndexOnlyScanInstrumentInitDSM(), ExecIndexScanInstrumentEstimate(), ExecIndexScanInstrumentInitDSM(), ExecInitParallelPlan(), ExecMemoizeEstimate(), ExecParallelRetrieveInstrumentation(), ExecParallelRetrieveJitInstrumentation(), ExecParallelSetupTupleQueues(), ExecSeqScanInstrumentEstimate(), ExecSeqScanInstrumentInitDSM(), ExecSortEstimate(), ExecTidRangeScanInstrumentEstimate(), ExecTidRangeScanInstrumentInitDSM(), hash_estimate_size(), InitializeParallelDSM(), MultiXactShmemRequest(), parallel_vacuum_init(), PGSemaphoreShmemRequest(), PMSignalShmemRequest(), PredicateLockShmemRequest(), ProcArrayShmemRequest(), ProcGlobalShmemRequest(), ProcSignalShmemRequest(), ReplicationOriginShmemRequest(), ReplicationSlotsShmemRequest(), SharedInvalShmemRequest(), shm_toc_estimate(), tuplesort_estimate_shared(), TwoPhaseShmemRequest(), WaitLSNShmemRequest(), WalSndShmemRequest(), and XLOGShmemRequest().

◆ pg_get_shmem_allocations()

Datum pg_get_shmem_allocations ( PG_FUNCTION_ARGS  )

Definition at line 1076 of file shmem.c.

1077{
1078#define PG_GET_SHMEM_SIZES_COLS 4
1079 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1084 bool nulls[PG_GET_SHMEM_SIZES_COLS];
1085
1086 InitMaterializedSRF(fcinfo, 0);
1087
1089
1091
1092 /* output all allocated entries */
1093 memset(nulls, 0, sizeof(nulls));
1094 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
1095 {
1096 values[0] = CStringGetTextDatum(ent->key);
1097 values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
1098 values[2] = Int64GetDatum(ent->size);
1099 values[3] = Int64GetDatum(ent->allocated_size);
1100 named_allocated += ent->allocated_size;
1101
1102 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1103 values, nulls);
1104 }
1105
1106 /* output shared memory allocated but not counted via the shmem index */
1107 values[0] = CStringGetTextDatum("<anonymous>");
1108 nulls[1] = true;
1110 values[3] = values[2];
1111 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1112
1113 /* output as-of-yet unused shared memory */
1114 nulls[0] = true;
1116 nulls[1] = false;
1118 values[3] = values[2];
1119 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1120
1122
1123 return (Datum) 0;
1124}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
@ LW_SHARED
Definition lwlock.h:105
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
uint64_t Datum
Definition postgres.h:70
#define PG_GET_SHMEM_SIZES_COLS
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785

References CStringGetTextDatum, fb(), ShmemAllocatorData::free_offset, hash_seq_init(), hash_seq_search(), InitMaterializedSRF(), Int64GetDatum(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PG_GET_SHMEM_SIZES_COLS, ShmemAllocator, ShmemIndex, ShmemIndexLock, ShmemSegHdr, PGShmemHeader::totalsize, tuplestore_putvalues(), and values.

◆ pg_get_shmem_allocations_numa()

Datum pg_get_shmem_allocations_numa ( PG_FUNCTION_ARGS  )

Definition at line 1133 of file shmem.c.

1134{
1135#define PG_GET_SHMEM_NUMA_SIZES_COLS 3
1136 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1140 bool nulls[PG_GET_SHMEM_NUMA_SIZES_COLS];
1142 void **page_ptrs;
1143 int *pages_status;
1146 max_nodes;
1147 Size *nodes;
1148
1149 if (pg_numa_init() == -1)
1150 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
1151
1152 InitMaterializedSRF(fcinfo, 0);
1153
1156
1157 /*
1158 * Shared memory allocations can vary in size and may not align with OS
1159 * memory page boundaries, while NUMA queries work on pages.
1160 *
1161 * To correctly map each allocation to NUMA nodes, we need to: 1.
1162 * Determine the OS memory page size. 2. Align each allocation's start/end
1163 * addresses to page boundaries. 3. Query NUMA node information for all
1164 * pages spanning the allocation.
1165 */
1167
1168 /*
1169 * Allocate memory for page pointers and status based on total shared
1170 * memory size. This simplified approach allocates enough space for all
1171 * pages in shared memory rather than calculating the exact requirements
1172 * for each segment.
1173 *
1174 * Add 1, because we don't know how exactly the segments align to OS
1175 * pages, so the allocation might use one more memory page. In practice
1176 * this is not very likely, and moreover we have more entries, each of
1177 * them using only fraction of the total pages.
1178 */
1182
1183 if (firstNumaTouch)
1184 elog(DEBUG1, "NUMA: page-faulting shared memory segments for proper NUMA readouts");
1185
1187
1189
1190 /* output all allocated entries */
1191 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
1192 {
1193 int i;
1194 char *startptr,
1195 *endptr;
1196 Size total_len;
1197
1198 /*
1199 * Calculate the range of OS pages used by this segment. The segment
1200 * may start / end half-way through a page, we want to count these
1201 * pages too. So we align the start/end pointers down/up, and then
1202 * calculate the number of pages from that.
1203 */
1204 startptr = (char *) TYPEALIGN_DOWN(os_page_size, ent->location);
1205 endptr = (char *) TYPEALIGN(os_page_size,
1206 (char *) ent->location + ent->allocated_size);
1207 total_len = (endptr - startptr);
1208
1209 shm_ent_page_count = total_len / os_page_size;
1210
1211 /*
1212 * If we ever get 0xff (-1) back from kernel inquiry, then we probably
1213 * have a bug in mapping buffers to OS pages.
1214 */
1215 memset(pages_status, 0xff, sizeof(int) * shm_ent_page_count);
1216
1217 /*
1218 * Setup page_ptrs[] with pointers to all OS pages for this segment,
1219 * and get the NUMA status using pg_numa_query_pages.
1220 *
1221 * In order to get reliable results we also need to touch memory
1222 * pages, so that inquiry about NUMA memory node doesn't return -2
1223 * (ENOENT, which indicates unmapped/unallocated pages).
1224 */
1225 for (i = 0; i < shm_ent_page_count; i++)
1226 {
1227 page_ptrs[i] = startptr + (i * os_page_size);
1228
1229 if (firstNumaTouch)
1231
1233 }
1234
1236 elog(ERROR, "failed NUMA pages inquiry status: %m");
1237
1238 /* Count number of NUMA nodes used for this shared memory entry */
1239 memset(nodes, 0, sizeof(Size) * (max_nodes + 2));
1240
1241 for (i = 0; i < shm_ent_page_count; i++)
1242 {
1243 int s = pages_status[i];
1244
1245 /* Ensure we are adding only valid index to the array */
1246 if (s >= 0 && s <= max_nodes)
1247 {
1248 /* valid NUMA node */
1249 nodes[s]++;
1250 continue;
1251 }
1252 else if (s == -2)
1253 {
1254 /* -2 means ENOENT (e.g. page was moved to swap) */
1255 nodes[max_nodes + 1]++;
1256 continue;
1257 }
1258
1259 elog(ERROR, "invalid NUMA node id outside of allowed range "
1260 "[0, " UINT64_FORMAT "]: %d", max_nodes, s);
1261 }
1262
1263 /* no NULLs for regular nodes */
1264 memset(nulls, 0, sizeof(nulls));
1265
1266 /*
1267 * Add one entry for each NUMA node, including those without allocated
1268 * memory for this segment.
1269 */
1270 for (i = 0; i <= max_nodes; i++)
1271 {
1272 values[0] = CStringGetTextDatum(ent->key);
1273 values[1] = Int32GetDatum(i);
1275
1276 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1277 values, nulls);
1278 }
1279
1280 /* The last entry is used for pages without a NUMA node. */
1281 nulls[1] = true;
1282 values[0] = CStringGetTextDatum(ent->key);
1284
1285 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1286 values, nulls);
1287 }
1288
1290 firstNumaTouch = false;
1291
1292 return (Datum) 0;
1293}
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:889
#define UINT64_FORMAT
Definition c.h:635
uint64_t uint64
Definition c.h:625
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition c.h:901
#define DEBUG1
Definition elog.h:31
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
int i
Definition isn.c:77
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
PGDLLIMPORT int pg_numa_get_max_node(void)
Definition pg_numa.c:138
#define pg_numa_touch_mem_if_required(ptr)
Definition pg_numa.h:37
PGDLLIMPORT int pg_numa_query_pages(int pid, unsigned long count, void **pages, int *status)
Definition pg_numa.c:132
PGDLLIMPORT int pg_numa_init(void)
Definition pg_numa.c:125
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
Size pg_get_shmem_pagesize(void)
Definition shmem.c:1304
#define PG_GET_SHMEM_NUMA_SIZES_COLS
static bool firstNumaTouch
Definition shmem.c:275

References CHECK_FOR_INTERRUPTS, CStringGetTextDatum, DEBUG1, elog, ERROR, fb(), firstNumaTouch, hash_seq_init(), hash_seq_search(), i, InitMaterializedSRF(), Int32GetDatum(), Int64GetDatum(), LW_SHARED, LWLockAcquire(), LWLockRelease(), palloc0_array, palloc_array, PG_GET_SHMEM_NUMA_SIZES_COLS, pg_get_shmem_pagesize(), pg_numa_get_max_node(), pg_numa_init(), pg_numa_query_pages(), pg_numa_touch_mem_if_required, ShmemIndex, ShmemIndexLock, ShmemSegHdr, PGShmemHeader::totalsize, tuplestore_putvalues(), TYPEALIGN, TYPEALIGN_DOWN, UINT64_FORMAT, and values.

◆ pg_get_shmem_pagesize()

Size pg_get_shmem_pagesize ( void  )

Definition at line 1304 of file shmem.c.

1305{
1307#ifdef WIN32
1309
1311 os_page_size = sysinfo.dwPageSize;
1312#else
1314#endif
1315
1318
1321
1322 return os_page_size;
1323}
int huge_pages_status
Definition guc_tables.c:610
@ HUGE_PAGES_UNKNOWN
Definition pg_shmem.h:56
@ HUGE_PAGES_ON
Definition pg_shmem.h:54
void GetHugePageSize(Size *hugepagesize, int *mmap_flags)
Definition sysv_shmem.c:480

References Assert, fb(), GetHugePageSize(), HUGE_PAGES_ON, huge_pages_status, HUGE_PAGES_UNKNOWN, and IsUnderPostmaster.

Referenced by pg_buffercache_os_pages_internal(), and pg_get_shmem_allocations_numa().

◆ pg_numa_available()

Datum pg_numa_available ( PG_FUNCTION_ARGS  )

Definition at line 1326 of file shmem.c.

1327{
1329}
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360

References pg_numa_init(), and PG_RETURN_BOOL.

◆ RegisterShmemCallbacks()

void RegisterShmemCallbacks ( const ShmemCallbacks callbacks)

Definition at line 874 of file shmem.c.

875{
877 {
878 /*
879 * After-startup initialization or attachment. Call the appropriate
880 * callbacks immediately.
881 */
882 if ((callbacks->flags & SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP) == 0)
883 elog(ERROR, "cannot request shared memory at this time");
884
886 }
887 else
888 {
889 /* Remember the callbacks for later */
891 (void *) callbacks);
892 }
893}
List * lappend(List *list, void *datum)
Definition list.c:339
static List * registered_shmem_callbacks
Definition shmem.c:158
static void CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
Definition shmem.c:899
#define SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP
Definition shmem.h:167

References CallShmemCallbacksAfterStartup(), elog, ERROR, ShmemCallbacks::flags, IsUnderPostmaster, lappend(), registered_shmem_callbacks, SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP, and SRS_DONE.

Referenced by _PG_init().

◆ ResetShmemAllocator()

void ResetShmemAllocator ( void  )

Definition at line 743 of file shmem.c.

744{
747
749
750 /*
751 * Note that we don't clear the registered callbacks. We will need to
752 * call them again as we restart
753 */
754}

References Assert, IsUnderPostmaster, NIL, pending_shmem_requests, and SRS_INITIAL.

Referenced by PostmasterStateMachine().

◆ ShmemAddrIsValid()

bool ShmemAddrIsValid ( const void addr)

Definition at line 850 of file shmem.c.

851{
852 return (addr >= ShmemBase) && (addr < ShmemEnd);
853}

References ShmemBase, and ShmemEnd.

Referenced by ReleasePredXact().

◆ ShmemAlloc()

void * ShmemAlloc ( Size  size)

Definition at line 764 of file shmem.c.

765{
766 void *newSpace;
767 Size allocated_size;
768
769 newSpace = ShmemAllocRaw(size, 0, &allocated_size);
770 if (!newSpace)
773 errmsg("out of shared memory (%zu bytes requested)",
774 size)));
775 return newSpace;
776}

References ereport, errcode(), errmsg, ERROR, fb(), and ShmemAllocRaw().

Referenced by InitShmemAllocator().

◆ ShmemAllocNoError()

void * ShmemAllocNoError ( Size  size)

Definition at line 784 of file shmem.c.

785{
786 Size allocated_size;
787
788 return ShmemAllocRaw(size, 0, &allocated_size);
789}

References ShmemAllocRaw().

◆ ShmemAllocRaw()

static void * ShmemAllocRaw ( Size  size,
Size  alignment,
Size allocated_size 
)
static

Definition at line 798 of file shmem.c.

799{
803 void *newSpace;
804
805 /*
806 * Ensure all space is adequately aligned. We used to only MAXALIGN this
807 * space but experience has proved that on modern systems that is not good
808 * enough. Many parts of the system are very sensitive to critical data
809 * structures getting split across cache line boundaries. To avoid that,
810 * attempt to align the beginning of the allocation to a cache line
811 * boundary. The calling code will still need to be careful about how it
812 * uses the allocated space - e.g. by padding each element in an array of
813 * structures out to a power-of-two size - but without this, even that
814 * won't be sufficient.
815 */
816 if (alignment < PG_CACHE_LINE_SIZE)
817 alignment = PG_CACHE_LINE_SIZE;
818
820
822
824 newStart = TYPEALIGN(alignment, rawStart);
825
826 newFree = newStart + size;
827 if (newFree <= ShmemSegHdr->totalsize)
828 {
829 newSpace = (char *) ShmemBase + newStart;
831 }
832 else
833 newSpace = NULL;
834
836
837 /* note this assert is okay with newSpace == NULL */
838 Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace));
839
840 *allocated_size = newFree - rawStart;
841 return newSpace;
842}
#define PG_CACHE_LINE_SIZE
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56

References Assert, fb(), ShmemAllocatorData::free_offset, PG_CACHE_LINE_SIZE, ShmemAllocatorData::shmem_lock, ShmemAllocator, ShmemBase, ShmemSegHdr, SpinLockAcquire(), SpinLockRelease(), and TYPEALIGN.

Referenced by InitShmemIndexEntry(), ShmemAlloc(), and ShmemAllocNoError().

◆ ShmemCallRequestCallbacks()

void ShmemCallRequestCallbacks ( void  )

Definition at line 979 of file shmem.c.

980{
981 ListCell *lc;
982
985
987 {
988 const ShmemCallbacks *callbacks = (const ShmemCallbacks *) lfirst(lc);
989
990 if (callbacks->request_fn)
991 callbacks->request_fn(callbacks->opaque_arg);
992 }
993}
#define lfirst(lc)
Definition pg_list.h:172

References Assert, fb(), lfirst, ShmemCallbacks::opaque_arg, registered_shmem_callbacks, ShmemCallbacks::request_fn, SRS_INITIAL, and SRS_REQUESTING.

Referenced by BootstrapModeMain(), PostgresSingleUserMain(), PostmasterMain(), and PostmasterStateMachine().

◆ ShmemGetRequestedSize()

size_t ShmemGetRequestedSize ( void  )

Definition at line 392 of file shmem.c.

393{
394 size_t size;
395
396 /* memory needed for the ShmemIndex */
398 sizeof(ShmemIndexEnt));
399 size = CACHELINEALIGN(size);
400
401 /* memory needed for all the requested areas */
403 {
404 size_t alignment = request->options->alignment;
405
406 /* pad the start address for alignment like ShmemAllocRaw() does */
407 if (alignment < PG_CACHE_LINE_SIZE)
408 alignment = PG_CACHE_LINE_SIZE;
409 size = TYPEALIGN(alignment, size);
410
411 size = add_size(size, request->options->size);
412 }
413
414 return size;
415}
Size add_size(Size s1, Size s2)
Definition shmem.c:1048

References add_size(), CACHELINEALIGN, fb(), foreach_ptr, hash_estimate_size(), list_length(), pending_shmem_requests, PG_CACHE_LINE_SIZE, SHMEM_INDEX_ADDITIONAL_SIZE, and TYPEALIGN.

Referenced by CalculateShmemSize().

◆ ShmemInitRequested()

void ShmemInitRequested ( void  )

Definition at line 425 of file shmem.c.

426{
427 /* should be called only by the postmaster or a standalone backend */
430
431 /*
432 * Initialize the ShmemIndex entries and perform basic initialization of
433 * all the requested memory areas. There are no concurrent processes yet,
434 * so no need for locking.
435 */
437 {
439 pfree(request->options);
440 }
443
444 /*
445 * Call the subsystem-specific init callbacks to finish initialization of
446 * all the areas.
447 */
449 {
450 if (callbacks->init_fn)
451 callbacks->init_fn(callbacks->opaque_arg);
452 }
453
455}

References Assert, fb(), foreach_ptr, InitShmemIndexEntry(), IsUnderPostmaster, list_free_deep(), NIL, pending_shmem_requests, pfree(), registered_shmem_callbacks, SRS_DONE, and SRS_INITIALIZING.

Referenced by CreateSharedMemoryAndSemaphores().

◆ ShmemInitStruct()

void * ShmemInitStruct ( const char name,
Size  size,
bool foundPtr 
)

Definition at line 1011 of file shmem.c.

1012{
1013 void *ptr = NULL;
1015 .name = name,
1016 .size = size,
1017 .ptr = &ptr,
1018 };
1020
1024
1026
1027 /*
1028 * During postmaster startup, look up the existing entry if any.
1029 */
1030 *foundPtr = false;
1033
1034 /* Initialize it if not found */
1035 if (!*foundPtr)
1037
1039
1040 Assert(ptr != NULL);
1041 return ptr;
1042}

References Assert, AttachShmemIndexEntry(), fb(), InitShmemIndexEntry(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), name, SHMEM_KIND_STRUCT, ShmemIndexLock, SRS_DONE, SRS_INITIALIZING, and SRS_REQUESTING.

Referenced by ShmemInitHash().

◆ ShmemRequestInternal()

void ShmemRequestInternal ( ShmemStructOpts options,
ShmemRequestKind  kind 
)

Definition at line 337 of file shmem.c.

338{
340
341 /* Check the options */
342 if (options->name == NULL)
343 elog(ERROR, "shared memory request is missing 'name' option");
344
346 {
347 if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
348 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
349 options->size, options->name);
350 }
351 else
352 {
354 elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
355 if (options->size <= 0)
356 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
357 options->size, options->name);
358 }
359
360 if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
361 elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
362 options->alignment, options->name);
363
364 /* Check that we're in the right state */
366 elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
367
368 /* Check that it's not already registered in this process */
370 {
371 if (strcmp(existing->options->name, options->name) == 0)
373 (errmsg("shared memory struct \"%s\" is already registered",
374 options->name)));
375 }
376
377 /* Request looks valid, remember it */
378 request = palloc(sizeof(ShmemRequest));
379 request->options = options;
380 request->kind = kind;
382}
void * palloc(Size size)
Definition mcxt.c:1387
#define pg_nextpower2_size_t

References elog, ereport, errmsg, ERROR, fb(), foreach_ptr, IsUnderPostmaster, lappend(), palloc(), pending_shmem_requests, pg_nextpower2_size_t, SHMEM_ATTACH_UNKNOWN_SIZE, and SRS_REQUESTING.

Referenced by ShmemRequestHashWithOpts(), ShmemRequestStructWithOpts(), and SimpleLruRequestWithOpts().

◆ ShmemRequestStructWithOpts()

void ShmemRequestStructWithOpts ( const ShmemStructOpts options)

Definition at line 316 of file shmem.c.

317{
319
321 sizeof(ShmemStructOpts));
323
325}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
MemoryContext TopMemoryContext
Definition mcxt.c:166
void ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
Definition shmem.c:337

References fb(), memcpy(), MemoryContextAlloc(), SHMEM_KIND_STRUCT, ShmemRequestInternal(), and TopMemoryContext.

Variable Documentation

◆ firstNumaTouch

bool firstNumaTouch = true
static

Definition at line 275 of file shmem.c.

Referenced by pg_get_shmem_allocations_numa().

◆ pending_shmem_requests

◆ registered_shmem_callbacks

List* registered_shmem_callbacks
static

Definition at line 158 of file shmem.c.

Referenced by RegisterShmemCallbacks(), ShmemCallRequestCallbacks(), and ShmemInitRequested().

◆ shmem_request_state

Definition at line 215 of file shmem.c.

◆ ShmemAllocator

ShmemAllocatorData* ShmemAllocator
static

Definition at line 247 of file shmem.c.

Referenced by InitShmemAllocator(), pg_get_shmem_allocations(), and ShmemAllocRaw().

◆ ShmemBase

void* ShmemBase
static

Definition at line 244 of file shmem.c.

Referenced by InitShmemAllocator(), ShmemAddrIsValid(), and ShmemAllocRaw().

◆ ShmemEnd

void* ShmemEnd
static

Definition at line 245 of file shmem.c.

Referenced by InitShmemAllocator(), and ShmemAddrIsValid().

◆ ShmemIndex

◆ ShmemSegHdr

PGShmemHeader* ShmemSegHdr
static