PostgreSQL Source Code git master
Loading...
Searching...
No Matches
shmem.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * shmem.c
4 * create shared memory and initialize shared memory data structures.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/storage/ipc/shmem.c
12 *
13 *-------------------------------------------------------------------------
14 */
15/*
16 * POSTGRES processes share one or more regions of shared memory.
17 * The shared memory is created by a postmaster and is inherited
18 * by each backend via fork() (or, in some ports, via other OS-specific
19 * methods). The routines in this file are used for allocating and
20 * binding to shared memory data structures.
21 *
22 * NOTES:
23 * (a) There are three kinds of shared memory data structures
24 * available to POSTGRES: fixed-size structures, queues and hash
25 * tables. Fixed-size structures contain things like global variables
26 * for a module and should never be allocated after the shared memory
27 * initialization phase. Hash tables have a fixed maximum size, but
28 * their actual size can vary dynamically. When entries are added
29 * to the table, more space is allocated. Queues link data structures
30 * that have been allocated either within fixed-size structures or as hash
31 * buckets. Each shared data structure has a string name to identify
32 * it (assigned in the module that declares it).
33 *
34 * (b) During initialization, each module looks for its
35 * shared data structures in a hash table called the "Shmem Index".
36 * If the data structure is not present, the caller can allocate
37 * a new one and initialize it. If the data structure is present,
38 * the caller "attaches" to the structure by initializing a pointer
39 * in the local address space.
40 * The shmem index has two purposes: first, it gives us
41 * a simple model of how the world looks when a backend process
42 * initializes. If something is present in the shmem index,
43 * it is initialized. If it is not, it is uninitialized. Second,
44 * the shmem index allows us to allocate shared memory on demand
45 * instead of trying to preallocate structures and hard-wire the
46 * sizes and locations in header files. If you are using a lot
47 * of shared memory in a lot of different places (and changing
48 * things during development), this is important.
49 *
50 * (c) In standard Unix-ish environments, individual backends do not
51 * need to re-establish their local pointers into shared memory, because
52 * they inherit correct values of those variables via fork() from the
53 * postmaster. However, this does not work in the EXEC_BACKEND case.
54 * In ports using EXEC_BACKEND, new backends have to set up their local
55 * pointers using the method described in (b) above.
56 *
57 * (d) memory allocation model: shared memory can never be
58 * freed, once allocated. Each hash table has its own free list,
59 * so hash buckets can be reused when an item is deleted. However,
60 * if one hash table grows very large and then shrinks, its space
61 * cannot be redistributed to other tables. We could build a simple
62 * hash bucket garbage collector if need be. Right now, it seems
63 * unnecessary.
64 */
65
66#include "postgres.h"
67
68#include <unistd.h>
69
70#include "common/int.h"
71#include "fmgr.h"
72#include "funcapi.h"
73#include "miscadmin.h"
74#include "port/pg_numa.h"
75#include "storage/lwlock.h"
76#include "storage/pg_shmem.h"
77#include "storage/shmem.h"
78#include "storage/spin.h"
79#include "utils/builtins.h"
80#include "utils/tuplestore.h"
81
82/*
83 * This is the first data structure stored in the shared memory segment, at
84 * the offset that PGShmemHeader->content_offset points to. Allocations by
85 * ShmemAlloc() are carved out of the space after this.
86 *
87 * For the base pointer and the total size of the shmem segment, we rely on
88 * the PGShmemHeader.
89 */
90typedef struct ShmemAllocatorData
91{
92 Size free_offset; /* offset to first free space from ShmemBase */
93 HASHHDR *index; /* location of ShmemIndex */
94
95 /* protects shared memory and LWLock allocation */
98
99static void *ShmemAllocRaw(Size size, Size *allocated_size);
100
101/* shared memory global variables */
102
103static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
104static void *ShmemBase; /* start address of shared memory */
105static void *ShmemEnd; /* end+1 address of shared memory */
106
108slock_t *ShmemLock; /* points to ShmemAllocator->shmem_lock */
109static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
110
111/* To get reliable results for NUMA inquiry we need to "touch pages" once */
112static bool firstNumaTouch = true;
113
115
116/*
117 * InitShmemAllocator() --- set up basic pointers to shared memory.
118 *
119 * Called at postmaster or stand-alone backend startup, to initialize the
120 * allocator's data structure in the shared memory segment. In EXEC_BACKEND,
121 * this is also called at backend startup, to set up pointers to the shared
122 * memory areas.
123 */
124void
126{
127 Assert(seghdr != NULL);
128
129 /*
130 * We assume the pointer and offset are MAXALIGN. Not a hard requirement,
131 * but it's true today and keeps the math below simpler.
132 */
133 Assert(seghdr == (void *) MAXALIGN(seghdr));
134 Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset));
135
138 ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
139
140#ifndef EXEC_BACKEND
142#endif
144 {
146
147 ShmemAllocator = (ShmemAllocatorData *) ((char *) shmhdr + shmhdr->content_offset);
149 }
150 else
151 {
152 Size offset;
153
154 /*
155 * Allocations after this point should go through ShmemAlloc, which
156 * expects to allocate everything on cache line boundaries. Make sure
157 * the first allocation begins on a cache line boundary.
158 */
159 offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
160 if (offset > seghdr->totalsize)
163 errmsg("out of shared memory (%zu bytes requested)",
164 offset)));
165
166 ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
167
170 ShmemAllocator->free_offset = offset;
171 /* ShmemIndex can't be set up yet (need LWLocks first) */
173 ShmemIndex = (HTAB *) NULL;
174 }
175}
176
177/*
178 * ShmemAlloc -- allocate max-aligned chunk from shared memory
179 *
180 * Throws error if request cannot be satisfied.
181 *
182 * Assumes ShmemLock and ShmemSegHdr are initialized.
183 */
184void *
186{
187 void *newSpace;
188 Size allocated_size;
189
190 newSpace = ShmemAllocRaw(size, &allocated_size);
191 if (!newSpace)
194 errmsg("out of shared memory (%zu bytes requested)",
195 size)));
196 return newSpace;
197}
198
199/*
200 * ShmemAllocNoError -- allocate max-aligned chunk from shared memory
201 *
202 * As ShmemAlloc, but returns NULL if out of space, rather than erroring.
203 */
204void *
206{
207 Size allocated_size;
208
209 return ShmemAllocRaw(size, &allocated_size);
210}
211
212/*
213 * ShmemAllocRaw -- allocate align chunk and return allocated size
214 *
215 * Also sets *allocated_size to the number of bytes allocated, which will
216 * be equal to the number requested plus any padding we choose to add.
217 */
218static void *
219ShmemAllocRaw(Size size, Size *allocated_size)
220{
223 void *newSpace;
224
225 /*
226 * Ensure all space is adequately aligned. We used to only MAXALIGN this
227 * space but experience has proved that on modern systems that is not good
228 * enough. Many parts of the system are very sensitive to critical data
229 * structures getting split across cache line boundaries. To avoid that,
230 * attempt to align the beginning of the allocation to a cache line
231 * boundary. The calling code will still need to be careful about how it
232 * uses the allocated space - e.g. by padding each element in an array of
233 * structures out to a power-of-two size - but without this, even that
234 * won't be sufficient.
235 */
236 size = CACHELINEALIGN(size);
237 *allocated_size = size;
238
240
242
244
245 newFree = newStart + size;
246 if (newFree <= ShmemSegHdr->totalsize)
247 {
248 newSpace = (char *) ShmemBase + newStart;
250 }
251 else
252 newSpace = NULL;
253
255
256 /* note this assert is okay with newSpace == NULL */
258
259 return newSpace;
260}
261
262/*
263 * ShmemAddrIsValid -- test if an address refers to shared memory
264 *
265 * Returns true if the pointer points within the shared memory segment.
266 */
267bool
268ShmemAddrIsValid(const void *addr)
269{
270 return (addr >= ShmemBase) && (addr < ShmemEnd);
271}
272
273/*
274 * InitShmemIndex() --- set up or attach to shmem index table.
275 */
276void
278{
279 HASHCTL info;
280
281 /*
282 * Create the shared memory shmem index.
283 *
284 * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
285 * hashtable to exist already, we have a bit of a circularity problem in
286 * initializing the ShmemIndex itself. The special "ShmemIndex" hash
287 * table name will tell ShmemInitStruct to fake it.
288 */
290 info.entrysize = sizeof(ShmemIndexEnt);
291
292 ShmemIndex = ShmemInitHash("ShmemIndex",
294 &info,
296}
297
298/*
299 * ShmemInitHash -- Create and initialize, or attach to, a
300 * shared memory hash table.
301 *
302 * We assume caller is doing some kind of synchronization
303 * so that two processes don't try to create/initialize the same
304 * table at once. (In practice, all creations are done in the postmaster
305 * process; child processes should always be attaching to existing tables.)
306 *
307 * max_size is the estimated maximum number of hashtable entries. This is
308 * not a hard limit, but the access efficiency will degrade if it is
309 * exceeded substantially (since it's used to compute directory size and
310 * the hash table buckets will get overfull).
311 *
312 * init_size is the number of hashtable entries to preallocate. For a table
313 * whose maximum size is certain, this should be equal to max_size; that
314 * ensures that no run-time out-of-shared-memory failures can occur.
315 *
316 * *infoP and hash_flags must specify at least the entry sizes and key
317 * comparison semantics (see hash_create()). Flag bits and values specific
318 * to shared-memory hash tables are added here, except that callers may
319 * choose to specify HASH_PARTITION and/or HASH_FIXED_SIZE.
320 *
321 * Note: before Postgres 9.0, this function returned NULL for some failure
322 * cases. Now, it always throws error instead, so callers need not check
323 * for NULL.
324 */
325HTAB *
326ShmemInitHash(const char *name, /* table string name for shmem index */
327 int64 init_size, /* initial table size */
328 int64 max_size, /* max size of the table */
329 HASHCTL *infoP, /* info about key and bucket size */
330 int hash_flags) /* info about infoP */
331{
332 bool found;
333 void *location;
334
335 /*
336 * Hash tables allocated in shared memory have a fixed directory; it can't
337 * grow or other backends wouldn't be able to find it. So, make sure we
338 * make it big enough to start with.
339 *
340 * The shared memory allocator must be specified too.
341 */
342 infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
343 infoP->alloc = ShmemAllocNoError;
345
346 /* look it up in the shmem index */
347 location = ShmemInitStruct(name,
349 &found);
350
351 /*
352 * if it already exists, attach to it rather than allocate and initialize
353 * new space
354 */
355 if (found)
357
358 /* Pass location of hashtable header to hash_create */
359 infoP->hctl = (HASHHDR *) location;
360
362}
363
364/*
365 * ShmemInitStruct -- Create/attach to a structure in shared memory.
366 *
367 * This is called during initialization to find or allocate
368 * a data structure in shared memory. If no other process
369 * has created the structure, this routine allocates space
370 * for it. If it exists already, a pointer to the existing
371 * structure is returned.
372 *
373 * Returns: pointer to the object. *foundPtr is set true if the object was
374 * already in the shmem index (hence, already initialized).
375 *
376 * Note: before Postgres 9.0, this function returned NULL for some failure
377 * cases. Now, it always throws error instead, so callers need not check
378 * for NULL.
379 */
380void *
381ShmemInitStruct(const char *name, Size size, bool *foundPtr)
382{
383 ShmemIndexEnt *result;
384 void *structPtr;
385
387
388 if (!ShmemIndex)
389 {
390 /* Must be trying to create/attach to ShmemIndex itself */
391 Assert(strcmp(name, "ShmemIndex") == 0);
392
394 {
395 /* Must be initializing a (non-standalone) backend */
398 *foundPtr = true;
399 }
400 else
401 {
402 /*
403 * If the shmem index doesn't exist, we are bootstrapping: we must
404 * be trying to init the shmem index itself.
405 *
406 * Notice that the ShmemIndexLock is released before the shmem
407 * index has been initialized. This should be OK because no other
408 * process can be accessing shared memory yet.
409 */
411 structPtr = ShmemAlloc(size);
413 *foundPtr = false;
414 }
416 return structPtr;
417 }
418
419 /* look it up in the shmem index */
420 result = (ShmemIndexEnt *)
422
423 if (!result)
424 {
428 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
429 name)));
430 }
431
432 if (*foundPtr)
433 {
434 /*
435 * Structure is in the shmem index so someone else has allocated it
436 * already. The size better be the same as the size we are trying to
437 * initialize to, or there is a name conflict (or worse).
438 */
439 if (result->size != size)
440 {
443 (errmsg("ShmemIndex entry size is wrong for data structure"
444 " \"%s\": expected %zu, actual %zu",
445 name, size, result->size)));
446 }
447 structPtr = result->location;
448 }
449 else
450 {
451 Size allocated_size;
452
453 /* It isn't in the table yet. allocate and initialize it */
454 structPtr = ShmemAllocRaw(size, &allocated_size);
455 if (structPtr == NULL)
456 {
457 /* out of memory; remove the failed ShmemIndex entry */
462 errmsg("not enough shared memory for data structure"
463 " \"%s\" (%zu bytes requested)",
464 name, size)));
465 }
466 result->size = size;
467 result->allocated_size = allocated_size;
468 result->location = structPtr;
469 }
470
472
474
476
477 return structPtr;
478}
479
480
481/*
482 * Add two Size values, checking for overflow
483 */
484Size
486{
487 Size result;
488
489 if (pg_add_size_overflow(s1, s2, &result))
492 errmsg("requested shared memory size overflows size_t")));
493 return result;
494}
495
496/*
497 * Multiply two Size values, checking for overflow
498 */
499Size
501{
502 Size result;
503
504 if (pg_mul_size_overflow(s1, s2, &result))
507 errmsg("requested shared memory size overflows size_t")));
508 return result;
509}
510
511/* SQL SRF showing allocated shared memory */
512Datum
514{
515#define PG_GET_SHMEM_SIZES_COLS 4
516 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
521 bool nulls[PG_GET_SHMEM_SIZES_COLS];
522
523 InitMaterializedSRF(fcinfo, 0);
524
526
528
529 /* output all allocated entries */
530 memset(nulls, 0, sizeof(nulls));
531 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
532 {
533 values[0] = CStringGetTextDatum(ent->key);
534 values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
535 values[2] = Int64GetDatum(ent->size);
536 values[3] = Int64GetDatum(ent->allocated_size);
537 named_allocated += ent->allocated_size;
538
539 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
540 values, nulls);
541 }
542
543 /* output shared memory allocated but not counted via the shmem index */
544 values[0] = CStringGetTextDatum("<anonymous>");
545 nulls[1] = true;
547 values[3] = values[2];
548 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
549
550 /* output as-of-yet unused shared memory */
551 nulls[0] = true;
553 nulls[1] = false;
555 values[3] = values[2];
556 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
557
559
560 return (Datum) 0;
561}
562
563/*
564 * SQL SRF showing NUMA memory nodes for allocated shared memory
565 *
566 * Compared to pg_get_shmem_allocations(), this function does not return
567 * information about shared anonymous allocations and unused shared memory.
568 */
569Datum
571{
572#define PG_GET_SHMEM_NUMA_SIZES_COLS 3
573 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
579 void **page_ptrs;
580 int *pages_status;
583 max_nodes;
584 Size *nodes;
585
586 if (pg_numa_init() == -1)
587 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
588
589 InitMaterializedSRF(fcinfo, 0);
590
593
594 /*
595 * Shared memory allocations can vary in size and may not align with OS
596 * memory page boundaries, while NUMA queries work on pages.
597 *
598 * To correctly map each allocation to NUMA nodes, we need to: 1.
599 * Determine the OS memory page size. 2. Align each allocation's start/end
600 * addresses to page boundaries. 3. Query NUMA node information for all
601 * pages spanning the allocation.
602 */
604
605 /*
606 * Allocate memory for page pointers and status based on total shared
607 * memory size. This simplified approach allocates enough space for all
608 * pages in shared memory rather than calculating the exact requirements
609 * for each segment.
610 *
611 * Add 1, because we don't know how exactly the segments align to OS
612 * pages, so the allocation might use one more memory page. In practice
613 * this is not very likely, and moreover we have more entries, each of
614 * them using only fraction of the total pages.
615 */
619
620 if (firstNumaTouch)
621 elog(DEBUG1, "NUMA: page-faulting shared memory segments for proper NUMA readouts");
622
624
626
627 /* output all allocated entries */
628 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
629 {
630 int i;
631 char *startptr,
632 *endptr;
633 Size total_len;
634
635 /*
636 * Calculate the range of OS pages used by this segment. The segment
637 * may start / end half-way through a page, we want to count these
638 * pages too. So we align the start/end pointers down/up, and then
639 * calculate the number of pages from that.
640 */
641 startptr = (char *) TYPEALIGN_DOWN(os_page_size, ent->location);
642 endptr = (char *) TYPEALIGN(os_page_size,
643 (char *) ent->location + ent->allocated_size);
644 total_len = (endptr - startptr);
645
646 shm_ent_page_count = total_len / os_page_size;
647
648 /*
649 * If we ever get 0xff (-1) back from kernel inquiry, then we probably
650 * have a bug in mapping buffers to OS pages.
651 */
652 memset(pages_status, 0xff, sizeof(int) * shm_ent_page_count);
653
654 /*
655 * Setup page_ptrs[] with pointers to all OS pages for this segment,
656 * and get the NUMA status using pg_numa_query_pages.
657 *
658 * In order to get reliable results we also need to touch memory
659 * pages, so that inquiry about NUMA memory node doesn't return -2
660 * (ENOENT, which indicates unmapped/unallocated pages).
661 */
662 for (i = 0; i < shm_ent_page_count; i++)
663 {
664 page_ptrs[i] = startptr + (i * os_page_size);
665
666 if (firstNumaTouch)
668
670 }
671
673 elog(ERROR, "failed NUMA pages inquiry status: %m");
674
675 /* Count number of NUMA nodes used for this shared memory entry */
676 memset(nodes, 0, sizeof(Size) * (max_nodes + 2));
677
678 for (i = 0; i < shm_ent_page_count; i++)
679 {
680 int s = pages_status[i];
681
682 /* Ensure we are adding only valid index to the array */
683 if (s >= 0 && s <= max_nodes)
684 {
685 /* valid NUMA node */
686 nodes[s]++;
687 continue;
688 }
689 else if (s == -2)
690 {
691 /* -2 means ENOENT (e.g. page was moved to swap) */
692 nodes[max_nodes + 1]++;
693 continue;
694 }
695
696 elog(ERROR, "invalid NUMA node id outside of allowed range "
697 "[0, " UINT64_FORMAT "]: %d", max_nodes, s);
698 }
699
700 /* no NULLs for regular nodes */
701 memset(nulls, 0, sizeof(nulls));
702
703 /*
704 * Add one entry for each NUMA node, including those without allocated
705 * memory for this segment.
706 */
707 for (i = 0; i <= max_nodes; i++)
708 {
709 values[0] = CStringGetTextDatum(ent->key);
710 values[1] = Int32GetDatum(i);
712
713 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
714 values, nulls);
715 }
716
717 /* The last entry is used for pages without a NUMA node. */
718 nulls[1] = true;
719 values[0] = CStringGetTextDatum(ent->key);
721
722 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
723 values, nulls);
724 }
725
727 firstNumaTouch = false;
728
729 return (Datum) 0;
730}
731
732/*
733 * Determine the memory page size used for the shared memory segment.
734 *
735 * If the shared segment was allocated using huge pages, returns the size of
736 * a huge page. Otherwise returns the size of regular memory page.
737 *
738 * This should be used only after the server is started.
739 */
740Size
742{
744#ifdef WIN32
746
748 os_page_size = sysinfo.dwPageSize;
749#else
751#endif
752
755
758
759 return os_page_size;
760}
761
762Datum
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define CACHELINEALIGN(LEN)
Definition c.h:901
#define MAXALIGN(LEN)
Definition c.h:898
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:891
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
#define UINT64_FORMAT
Definition c.h:637
uint64_t uint64
Definition c.h:619
size_t Size
Definition c.h:691
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition c.h:903
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
Size hash_get_shared_size(HASHCTL *info, int flags)
Definition dynahash.c:854
int64 hash_select_dirsize(int64 num_entries)
Definition dynahash.c:830
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
int errcode(int sqlerrcode)
Definition elog.c:874
#define DEBUG1
Definition elog.h:30
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition funcapi.c:76
bool IsUnderPostmaster
Definition globals.c:120
int huge_pages_status
Definition guc_tables.c:592
#define HASH_STRINGS
Definition hsearch.h:96
@ HASH_REMOVE
Definition hsearch.h:115
@ HASH_ENTER_NULL
Definition hsearch.h:116
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_ALLOC
Definition hsearch.h:101
#define HASH_DIRSIZE
Definition hsearch.h:94
#define HASH_ATTACH
Definition hsearch.h:104
#define HASH_SHARED_MEM
Definition hsearch.h:103
static bool pg_mul_size_overflow(size_t a, size_t b, size_t *result)
Definition int.h:642
static bool pg_add_size_overflow(size_t a, size_t b, size_t *result)
Definition int.h:608
int i
Definition isn.c:77
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1177
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1794
@ LW_SHARED
Definition lwlock.h:113
@ LW_EXCLUSIVE
Definition lwlock.h:112
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static char * errmsg
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
@ HUGE_PAGES_UNKNOWN
Definition pg_shmem.h:56
@ HUGE_PAGES_ON
Definition pg_shmem.h:54
static Datum Int64GetDatum(int64 X)
Definition postgres.h:413
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static int fb(int x)
char * s1
char * s2
bool ShmemAddrIsValid(const void *addr)
Definition shmem.c:268
Datum pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
Definition shmem.c:570
Datum pg_numa_available(PG_FUNCTION_ARGS)
Definition shmem.c:763
void InitShmemAllocator(PGShmemHeader *seghdr)
Definition shmem.c:125
static void * ShmemBase
Definition shmem.c:104
Datum pg_get_shmem_allocations(PG_FUNCTION_ARGS)
Definition shmem.c:513
void InitShmemIndex(void)
Definition shmem.c:277
static void * ShmemEnd
Definition shmem.c:105
Size add_size(Size s1, Size s2)
Definition shmem.c:485
Size pg_get_shmem_pagesize(void)
Definition shmem.c:741
#define PG_GET_SHMEM_NUMA_SIZES_COLS
void * ShmemAllocNoError(Size size)
Definition shmem.c:205
Size mul_size(Size s1, Size s2)
Definition shmem.c:500
void * ShmemAlloc(Size size)
Definition shmem.c:185
slock_t * ShmemLock
Definition shmem.c:108
HTAB * ShmemInitHash(const char *name, int64 init_size, int64 max_size, HASHCTL *infoP, int hash_flags)
Definition shmem.c:326
#define PG_GET_SHMEM_SIZES_COLS
static PGShmemHeader * ShmemSegHdr
Definition shmem.c:103
static void * ShmemAllocRaw(Size size, Size *allocated_size)
Definition shmem.c:219
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:381
static HTAB * ShmemIndex
Definition shmem.c:109
static ShmemAllocatorData * ShmemAllocator
Definition shmem.c:107
static bool firstNumaTouch
Definition shmem.c:112
#define SHMEM_INDEX_SIZE
Definition shmem.h:52
#define SHMEM_INDEX_KEYSIZE
Definition shmem.h:50
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
Size keysize
Definition hsearch.h:75
Size entrysize
Definition hsearch.h:76
Size totalsize
Definition pg_shmem.h:34
HASHHDR * index
Definition shmem.c:93
slock_t shmem_lock
Definition shmem.c:96
void * location
Definition shmem.h:58
Size size
Definition shmem.h:59
Size allocated_size
Definition shmem.h:60
void GetHugePageSize(Size *hugepagesize, int *mmap_flags)
Definition sysv_shmem.c:480
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785
const char * name