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 1043 of file shmem.c.

1044{
1045 Size result;
1046
1048 ereport(ERROR,
1050 errmsg("requested shared memory size overflows size_t")));
1051 return result;
1052}
size_t Size
Definition c.h:689
uint32 result
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:151
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(), ExecBitmapHeapEstimate(), ExecBitmapHeapInitializeDSM(), ExecHashEstimate(), ExecIncrementalSortEstimate(), ExecMemoizeEstimate(), ExecSortEstimate(), 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 578 of file shmem.c.

579{
580 const char *name = request->options->name;
582
583 /* Look it up in the shmem index */
586 if (!index_entry)
587 {
588 if (!missing_ok)
590 (errmsg("could not find ShmemIndex entry for data structure \"%s\"",
591 request->options->name)));
592 return false;
593 }
594
595 /* Check that the size in the index matches the request */
596 if (index_entry->size != request->options->size &&
597 request->options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
598 {
600 (errmsg("shared memory struct \"%s\" was created with"
601 " different size: existing %zu, requested %zu",
602 name, index_entry->size, request->options->size)));
603 }
604
605 /*
606 * Re-establish the caller's pointer variable, or do other actions to
607 * attach depending on the kind of shmem area it is.
608 */
609 switch (request->kind)
610 {
612 if (request->options->ptr)
613 *(request->options->ptr) = index_entry->location;
614 break;
615 case SHMEM_KIND_HASH:
616 shmem_hash_attach(index_entry->location, request->options);
617 break;
618 case SHMEM_KIND_SLRU:
619 shmem_slru_attach(index_entry->location, request->options);
620 break;
621 }
622
623 return true;
624}
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 896 of file shmem.c.

897{
898 bool found_any;
899 bool notfound_any;
900
903
904 /*
905 * Call the request callback first. The callback makes ShmemRequest*()
906 * calls for each shmem area, adding them to pending_shmem_requests.
907 */
909 if (callbacks->request_fn)
910 callbacks->request_fn(callbacks->opaque_arg);
912
914 {
916 return;
917 }
918
919 /* Hold ShmemIndexLock while we allocate all the shmem entries */
921
922 /*
923 * Check if the requested shared memory areas have already been
924 * initialized. We assume all the areas requested by the request callback
925 * to form a coherent unit such that they're all already initialized or
926 * none. Otherwise it would be ambiguous which callback, init or attach,
927 * to callback afterwards.
928 */
929 found_any = notfound_any = false;
931 {
932 if (hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL))
933 found_any = true;
934 else
935 notfound_any = true;
936 }
937 if (found_any && notfound_any)
938 elog(ERROR, "found some but not all");
939
940 /*
941 * Allocate or attach all the shmem areas requested by the request_fn
942 * callback.
943 */
945 {
946 if (found_any)
948 else
950 }
953
954 /* Finish by calling the appropriate subsystem-specific callback */
955 if (found_any)
956 {
957 if (callbacks->attach_fn)
958 callbacks->attach_fn(callbacks->opaque_arg);
959 }
960 else
961 {
962 if (callbacks->init_fn)
963 callbacks->init_fn(callbacks->opaque_arg);
964 }
965
968}
#define Assert(condition)
Definition c.h:943
#define elog(elevel,...)
Definition elog.h:227
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
#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:509
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:578
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, 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 635 of file shmem.c.

636{
637 Size offset;
639 HASHCTL info;
640 int hash_flags;
641
642#ifndef EXEC_BACKEND
644#endif
645 Assert(seghdr != NULL);
646
648 {
650 }
651 else
652 {
655 }
656
657 /*
658 * We assume the pointer and offset are MAXALIGN. Not a hard requirement,
659 * but it's true today and keeps the math below simpler.
660 */
661 Assert(seghdr == (void *) MAXALIGN(seghdr));
662 Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset));
663
664 /*
665 * Allocations after this point should go through ShmemAlloc, which
666 * expects to allocate everything on cache line boundaries. Make sure the
667 * first allocation begins on a cache line boundary.
668 */
669 offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
670 if (offset > seghdr->totalsize)
673 errmsg("out of shared memory (%zu bytes requested)",
674 offset)));
675
676 /*
677 * In postmaster or stand-alone backend, initialize the shared memory
678 * allocator so that we can allocate shared memory for ShmemIndex using
679 * ShmemAlloc(). In a regular backend just set up the pointers required
680 * by ShmemAlloc().
681 */
682 ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
684 {
686 ShmemAllocator->free_offset = offset;
688 }
689
692 ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
693
694 /*
695 * Create (or attach to) the shared memory index of shmem areas.
696 *
697 * This is the same initialization as ShmemInitHash() does, but we cannot
698 * use ShmemInitHash() here because it relies on ShmemIndex being already
699 * initialized.
700 */
702
704 info.entrysize = sizeof(ShmemIndexEnt);
705 hash_flags = HASH_ELEM | HASH_STRINGS | HASH_FIXED_SIZE;
706
708 {
711 }
715 "ShmemIndex", hash_nelems,
716 &info, hash_flags);
718
719 /*
720 * Add an entry for ShmemIndex itself into ShmemIndex, so that it's
721 * visible in the pg_shmem_allocations view
722 */
724 {
725 bool found;
727 hash_search(ShmemIndex, "ShmemIndex", HASH_ENTER, &found);
728
729 Assert(!found);
731 result->allocated_size = ShmemAllocator->index_size;
732 result->location = ShmemAllocator->index;
733 }
734}
#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:120
#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:761
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 509 of file shmem.c.

510{
511 const char *name = request->options->name;
513 bool found;
514 size_t allocated_size;
515 void *structPtr;
516
517 /* look it up in the shmem index */
520 if (found)
521 elog(ERROR, "shared memory struct \"%s\" is already initialized", name);
522 if (!index_entry)
523 {
524 /* tried to add it to the hash table, but there was no space */
527 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
528 name)));
529 }
530
531 /*
532 * We inserted the entry to the shared memory index. Allocate requested
533 * amount of shared memory for it, and initialize the index entry.
534 */
535 structPtr = ShmemAllocRaw(request->options->size,
536 request->options->alignment,
537 &allocated_size);
538 if (structPtr == NULL)
539 {
540 /* out of memory; remove the failed ShmemIndex entry */
544 errmsg("not enough shared memory for data structure"
545 " \"%s\" (%zu bytes requested)",
546 name, request->options->size)));
547 }
548 index_entry->size = request->options->size;
549 index_entry->allocated_size = allocated_size;
550 index_entry->location = structPtr;
551
552 /* Initialize depending on the kind of shmem area it is */
553 switch (request->kind)
554 {
556 if (request->options->ptr)
557 *(request->options->ptr) = index_entry->location;
558 break;
559 case SHMEM_KIND_HASH:
561 break;
562 case SHMEM_KIND_SLRU:
564 break;
565 }
566}
@ 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:795
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 1058 of file shmem.c.

1059{
1060 Size result;
1061
1063 ereport(ERROR,
1065 errmsg("requested shared memory size overflows size_t")));
1066 return result;
1067}
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(), ExecBitmapHeapEstimate(), ExecBitmapHeapInitializeDSM(), ExecHashEstimate(), ExecIncrementalSortEstimate(), ExecInitParallelPlan(), ExecMemoizeEstimate(), ExecParallelRetrieveInstrumentation(), ExecParallelRetrieveJitInstrumentation(), ExecParallelSetupTupleQueues(), ExecSortEstimate(), 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 1071 of file shmem.c.

1072{
1073#define PG_GET_SHMEM_SIZES_COLS 4
1074 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1079 bool nulls[PG_GET_SHMEM_SIZES_COLS];
1080
1081 InitMaterializedSRF(fcinfo, 0);
1082
1084
1086
1087 /* output all allocated entries */
1088 memset(nulls, 0, sizeof(nulls));
1089 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
1090 {
1091 values[0] = CStringGetTextDatum(ent->key);
1092 values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
1093 values[2] = Int64GetDatum(ent->size);
1094 values[3] = Int64GetDatum(ent->allocated_size);
1095 named_allocated += ent->allocated_size;
1096
1097 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1098 values, nulls);
1099 }
1100
1101 /* output shared memory allocated but not counted via the shmem index */
1102 values[0] = CStringGetTextDatum("<anonymous>");
1103 nulls[1] = true;
1105 values[3] = values[2];
1106 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1107
1108 /* output as-of-yet unused shared memory */
1109 nulls[0] = true;
1111 nulls[1] = false;
1113 values[3] = values[2];
1114 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1115
1117
1118 return (Datum) 0;
1119}
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:413
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 1128 of file shmem.c.

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

1300{
1302#ifdef WIN32
1304
1306 os_page_size = sysinfo.dwPageSize;
1307#else
1309#endif
1310
1313
1316
1317 return os_page_size;
1318}
int huge_pages_status
Definition guc_tables.c:600
@ 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 1321 of file shmem.c.

1322{
1324}
#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 871 of file shmem.c.

872{
874 {
875 /*
876 * After-startup initialization or attachment. Call the appropriate
877 * callbacks immediately.
878 */
879 if ((callbacks->flags & SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP) == 0)
880 elog(ERROR, "cannot request shared memory at this time");
881
883 }
884 else
885 {
886 /* Remember the callbacks for later */
888 (void *) callbacks);
889 }
890}
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:896
#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 740 of file shmem.c.

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

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

Referenced by PostmasterStateMachine().

◆ ShmemAddrIsValid()

bool ShmemAddrIsValid ( const void addr)

Definition at line 847 of file shmem.c.

848{
849 return (addr >= ShmemBase) && (addr < ShmemEnd);
850}

References ShmemBase, and ShmemEnd.

Referenced by ReleasePredXact().

◆ ShmemAlloc()

void * ShmemAlloc ( Size  size)

Definition at line 761 of file shmem.c.

762{
763 void *newSpace;
764 Size allocated_size;
765
766 newSpace = ShmemAllocRaw(size, 0, &allocated_size);
767 if (!newSpace)
770 errmsg("out of shared memory (%zu bytes requested)",
771 size)));
772 return newSpace;
773}

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

Referenced by InitShmemAllocator(), and StatsShmemInit().

◆ ShmemAllocNoError()

void * ShmemAllocNoError ( Size  size)

Definition at line 781 of file shmem.c.

782{
783 Size allocated_size;
784
785 return ShmemAllocRaw(size, 0, &allocated_size);
786}

References ShmemAllocRaw().

◆ ShmemAllocRaw()

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

Definition at line 795 of file shmem.c.

796{
800 void *newSpace;
801
802 /*
803 * Ensure all space is adequately aligned. We used to only MAXALIGN this
804 * space but experience has proved that on modern systems that is not good
805 * enough. Many parts of the system are very sensitive to critical data
806 * structures getting split across cache line boundaries. To avoid that,
807 * attempt to align the beginning of the allocation to a cache line
808 * boundary. The calling code will still need to be careful about how it
809 * uses the allocated space - e.g. by padding each element in an array of
810 * structures out to a power-of-two size - but without this, even that
811 * won't be sufficient.
812 */
813 if (alignment < PG_CACHE_LINE_SIZE)
814 alignment = PG_CACHE_LINE_SIZE;
815
817
819
821 newStart = TYPEALIGN(alignment, rawStart);
822
823 newFree = newStart + size;
824 if (newFree <= ShmemSegHdr->totalsize)
825 {
826 newSpace = (char *) ShmemBase + newStart;
828 }
829 else
830 newSpace = NULL;
831
833
834 /* note this assert is okay with newSpace == NULL */
835 Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace));
836
837 *allocated_size = newFree - rawStart;
838 return newSpace;
839}
#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 974 of file shmem.c.

975{
976 ListCell *lc;
977
980
982 {
983 const ShmemCallbacks *callbacks = (const ShmemCallbacks *) lfirst(lc);
984
985 if (callbacks->request_fn)
986 callbacks->request_fn(callbacks->opaque_arg);
987 }
988}
#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 391 of file shmem.c.

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

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 424 of file shmem.c.

425{
426 /* should be called only by the postmaster or a standalone backend */
429
430 /*
431 * Initialize the ShmemIndex entries and perform basic initialization of
432 * all the requested memory areas. There are no concurrent processes yet,
433 * so no need for locking.
434 */
436 {
438 }
441
442 /*
443 * Call the subsystem-specific init callbacks to finish initialization of
444 * all the areas.
445 */
447 {
448 if (callbacks->init_fn)
449 callbacks->init_fn(callbacks->opaque_arg);
450 }
451
453}

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

Referenced by CreateSharedMemoryAndSemaphores().

◆ ShmemInitStruct()

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

Definition at line 1006 of file shmem.c.

1007{
1008 void *ptr = NULL;
1010 .name = name,
1011 .size = size,
1012 .ptr = &ptr,
1013 };
1015
1019
1021
1022 /*
1023 * During postmaster startup, look up the existing entry if any.
1024 */
1025 *foundPtr = false;
1028
1029 /* Initialize it if not found */
1030 if (!*foundPtr)
1032
1034
1035 Assert(ptr != NULL);
1036 return ptr;
1037}

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 336 of file shmem.c.

337{
339
340 /* Check the options */
341 if (options->name == NULL)
342 elog(ERROR, "shared memory request is missing 'name' option");
343
345 {
346 if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
347 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
348 options->size, options->name);
349 }
350 else
351 {
353 elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
354 if (options->size <= 0)
355 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
356 options->size, options->name);
357 }
358
359 if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
360 elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
361 options->alignment, options->name);
362
363 /* Check that we're in the right state */
365 elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
366
367 /* Check that it's not already registered in this process */
369 {
370 if (strcmp(existing->options->name, options->name) == 0)
372 (errmsg("shared memory struct \"%s\" is already registered",
373 options->name)));
374 }
375
376 /* Request looks valid, remember it */
377 request = palloc(sizeof(ShmemRequest));
378 request->options = options;
379 request->kind = kind;
381}
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:336

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