PostgreSQL Source Code git master
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-2025, 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 "common/int.h"
69#include "fmgr.h"
70#include "funcapi.h"
71#include "miscadmin.h"
72#include "port/pg_numa.h"
73#include "storage/lwlock.h"
74#include "storage/pg_shmem.h"
75#include "storage/shmem.h"
76#include "storage/spin.h"
77#include "utils/builtins.h"
78
79static void *ShmemAllocRaw(Size size, Size *allocated_size);
80static void *ShmemAllocUnlocked(Size size);
81
82/* shared memory global variables */
83
84static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
85
86static void *ShmemBase; /* start address of shared memory */
87
88static void *ShmemEnd; /* end+1 address of shared memory */
89
90slock_t *ShmemLock; /* spinlock for shared memory and LWLock
91 * allocation */
92
93static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
94
95/* To get reliable results for NUMA inquiry we need to "touch pages" once */
96static bool firstNumaTouch = true;
97
99
100/*
101 * InitShmemAccess() --- set up basic pointers to shared memory.
102 */
103void
105{
106 ShmemSegHdr = seghdr;
107 ShmemBase = seghdr;
108 ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
109}
110
111/*
112 * InitShmemAllocation() --- set up shared-memory space allocation.
113 *
114 * This should be called only in the postmaster or a standalone backend.
115 */
116void
118{
119 PGShmemHeader *shmhdr = ShmemSegHdr;
120 char *aligned;
121
122 Assert(shmhdr != NULL);
123
124 /*
125 * Initialize the spinlock used by ShmemAlloc. We must use
126 * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
127 */
128 ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t));
129
131
132 /*
133 * Allocations after this point should go through ShmemAlloc, which
134 * expects to allocate everything on cache line boundaries. Make sure the
135 * first allocation begins on a cache line boundary.
136 */
137 aligned = (char *)
138 (CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset)));
139 shmhdr->freeoffset = aligned - (char *) shmhdr;
140
141 /* ShmemIndex can't be set up yet (need LWLocks first) */
142 shmhdr->index = NULL;
143 ShmemIndex = (HTAB *) NULL;
144}
145
146/*
147 * ShmemAlloc -- allocate max-aligned chunk from shared memory
148 *
149 * Throws error if request cannot be satisfied.
150 *
151 * Assumes ShmemLock and ShmemSegHdr are initialized.
152 */
153void *
155{
156 void *newSpace;
157 Size allocated_size;
158
159 newSpace = ShmemAllocRaw(size, &allocated_size);
160 if (!newSpace)
162 (errcode(ERRCODE_OUT_OF_MEMORY),
163 errmsg("out of shared memory (%zu bytes requested)",
164 size)));
165 return newSpace;
166}
167
168/*
169 * ShmemAllocNoError -- allocate max-aligned chunk from shared memory
170 *
171 * As ShmemAlloc, but returns NULL if out of space, rather than erroring.
172 */
173void *
175{
176 Size allocated_size;
177
178 return ShmemAllocRaw(size, &allocated_size);
179}
180
181/*
182 * ShmemAllocRaw -- allocate align chunk and return allocated size
183 *
184 * Also sets *allocated_size to the number of bytes allocated, which will
185 * be equal to the number requested plus any padding we choose to add.
186 */
187static void *
188ShmemAllocRaw(Size size, Size *allocated_size)
189{
190 Size newStart;
191 Size newFree;
192 void *newSpace;
193
194 /*
195 * Ensure all space is adequately aligned. We used to only MAXALIGN this
196 * space but experience has proved that on modern systems that is not good
197 * enough. Many parts of the system are very sensitive to critical data
198 * structures getting split across cache line boundaries. To avoid that,
199 * attempt to align the beginning of the allocation to a cache line
200 * boundary. The calling code will still need to be careful about how it
201 * uses the allocated space - e.g. by padding each element in an array of
202 * structures out to a power-of-two size - but without this, even that
203 * won't be sufficient.
204 */
205 size = CACHELINEALIGN(size);
206 *allocated_size = size;
207
208 Assert(ShmemSegHdr != NULL);
209
211
212 newStart = ShmemSegHdr->freeoffset;
213
214 newFree = newStart + size;
215 if (newFree <= ShmemSegHdr->totalsize)
216 {
217 newSpace = (char *) ShmemBase + newStart;
218 ShmemSegHdr->freeoffset = newFree;
219 }
220 else
221 newSpace = NULL;
222
224
225 /* note this assert is okay with newSpace == NULL */
226 Assert(newSpace == (void *) CACHELINEALIGN(newSpace));
227
228 return newSpace;
229}
230
231/*
232 * ShmemAllocUnlocked -- allocate max-aligned chunk from shared memory
233 *
234 * Allocate space without locking ShmemLock. This should be used for,
235 * and only for, allocations that must happen before ShmemLock is ready.
236 *
237 * We consider maxalign, rather than cachealign, sufficient here.
238 */
239static void *
241{
242 Size newStart;
243 Size newFree;
244 void *newSpace;
245
246 /*
247 * Ensure allocated space is adequately aligned.
248 */
249 size = MAXALIGN(size);
250
251 Assert(ShmemSegHdr != NULL);
252
253 newStart = ShmemSegHdr->freeoffset;
254
255 newFree = newStart + size;
256 if (newFree > ShmemSegHdr->totalsize)
258 (errcode(ERRCODE_OUT_OF_MEMORY),
259 errmsg("out of shared memory (%zu bytes requested)",
260 size)));
261 ShmemSegHdr->freeoffset = newFree;
262
263 newSpace = (char *) ShmemBase + newStart;
264
265 Assert(newSpace == (void *) MAXALIGN(newSpace));
266
267 return newSpace;
268}
269
270/*
271 * ShmemAddrIsValid -- test if an address refers to shared memory
272 *
273 * Returns true if the pointer points within the shared memory segment.
274 */
275bool
276ShmemAddrIsValid(const void *addr)
277{
278 return (addr >= ShmemBase) && (addr < ShmemEnd);
279}
280
281/*
282 * InitShmemIndex() --- set up or attach to shmem index table.
283 */
284void
286{
287 HASHCTL info;
288
289 /*
290 * Create the shared memory shmem index.
291 *
292 * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
293 * hashtable to exist already, we have a bit of a circularity problem in
294 * initializing the ShmemIndex itself. The special "ShmemIndex" hash
295 * table name will tell ShmemInitStruct to fake it.
296 */
298 info.entrysize = sizeof(ShmemIndexEnt);
299
300 ShmemIndex = ShmemInitHash("ShmemIndex",
302 &info,
304}
305
306/*
307 * ShmemInitHash -- Create and initialize, or attach to, a
308 * shared memory hash table.
309 *
310 * We assume caller is doing some kind of synchronization
311 * so that two processes don't try to create/initialize the same
312 * table at once. (In practice, all creations are done in the postmaster
313 * process; child processes should always be attaching to existing tables.)
314 *
315 * max_size is the estimated maximum number of hashtable entries. This is
316 * not a hard limit, but the access efficiency will degrade if it is
317 * exceeded substantially (since it's used to compute directory size and
318 * the hash table buckets will get overfull).
319 *
320 * init_size is the number of hashtable entries to preallocate. For a table
321 * whose maximum size is certain, this should be equal to max_size; that
322 * ensures that no run-time out-of-shared-memory failures can occur.
323 *
324 * *infoP and hash_flags must specify at least the entry sizes and key
325 * comparison semantics (see hash_create()). Flag bits and values specific
326 * to shared-memory hash tables are added here, except that callers may
327 * choose to specify HASH_PARTITION and/or HASH_FIXED_SIZE.
328 *
329 * Note: before Postgres 9.0, this function returned NULL for some failure
330 * cases. Now, it always throws error instead, so callers need not check
331 * for NULL.
332 */
333HTAB *
334ShmemInitHash(const char *name, /* table string name for shmem index */
335 int64 init_size, /* initial table size */
336 int64 max_size, /* max size of the table */
337 HASHCTL *infoP, /* info about key and bucket size */
338 int hash_flags) /* info about infoP */
339{
340 bool found;
341 void *location;
342
343 /*
344 * Hash tables allocated in shared memory have a fixed directory; it can't
345 * grow or other backends wouldn't be able to find it. So, make sure we
346 * make it big enough to start with.
347 *
348 * The shared memory allocator must be specified too.
349 */
350 infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
351 infoP->alloc = ShmemAllocNoError;
352 hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
353
354 /* look it up in the shmem index */
355 location = ShmemInitStruct(name,
356 hash_get_shared_size(infoP, hash_flags),
357 &found);
358
359 /*
360 * if it already exists, attach to it rather than allocate and initialize
361 * new space
362 */
363 if (found)
364 hash_flags |= HASH_ATTACH;
365
366 /* Pass location of hashtable header to hash_create */
367 infoP->hctl = (HASHHDR *) location;
368
369 return hash_create(name, init_size, infoP, hash_flags);
370}
371
372/*
373 * ShmemInitStruct -- Create/attach to a structure in shared memory.
374 *
375 * This is called during initialization to find or allocate
376 * a data structure in shared memory. If no other process
377 * has created the structure, this routine allocates space
378 * for it. If it exists already, a pointer to the existing
379 * structure is returned.
380 *
381 * Returns: pointer to the object. *foundPtr is set true if the object was
382 * already in the shmem index (hence, already initialized).
383 *
384 * Note: before Postgres 9.0, this function returned NULL for some failure
385 * cases. Now, it always throws error instead, so callers need not check
386 * for NULL.
387 */
388void *
389ShmemInitStruct(const char *name, Size size, bool *foundPtr)
390{
391 ShmemIndexEnt *result;
392 void *structPtr;
393
394 LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
395
396 if (!ShmemIndex)
397 {
398 PGShmemHeader *shmemseghdr = ShmemSegHdr;
399
400 /* Must be trying to create/attach to ShmemIndex itself */
401 Assert(strcmp(name, "ShmemIndex") == 0);
402
404 {
405 /* Must be initializing a (non-standalone) backend */
406 Assert(shmemseghdr->index != NULL);
407 structPtr = shmemseghdr->index;
408 *foundPtr = true;
409 }
410 else
411 {
412 /*
413 * If the shmem index doesn't exist, we are bootstrapping: we must
414 * be trying to init the shmem index itself.
415 *
416 * Notice that the ShmemIndexLock is released before the shmem
417 * index has been initialized. This should be OK because no other
418 * process can be accessing shared memory yet.
419 */
420 Assert(shmemseghdr->index == NULL);
421 structPtr = ShmemAlloc(size);
422 shmemseghdr->index = structPtr;
423 *foundPtr = false;
424 }
425 LWLockRelease(ShmemIndexLock);
426 return structPtr;
427 }
428
429 /* look it up in the shmem index */
430 result = (ShmemIndexEnt *)
432
433 if (!result)
434 {
435 LWLockRelease(ShmemIndexLock);
437 (errcode(ERRCODE_OUT_OF_MEMORY),
438 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
439 name)));
440 }
441
442 if (*foundPtr)
443 {
444 /*
445 * Structure is in the shmem index so someone else has allocated it
446 * already. The size better be the same as the size we are trying to
447 * initialize to, or there is a name conflict (or worse).
448 */
449 if (result->size != size)
450 {
451 LWLockRelease(ShmemIndexLock);
453 (errmsg("ShmemIndex entry size is wrong for data structure"
454 " \"%s\": expected %zu, actual %zu",
455 name, size, result->size)));
456 }
457 structPtr = result->location;
458 }
459 else
460 {
461 Size allocated_size;
462
463 /* It isn't in the table yet. allocate and initialize it */
464 structPtr = ShmemAllocRaw(size, &allocated_size);
465 if (structPtr == NULL)
466 {
467 /* out of memory; remove the failed ShmemIndex entry */
469 LWLockRelease(ShmemIndexLock);
471 (errcode(ERRCODE_OUT_OF_MEMORY),
472 errmsg("not enough shared memory for data structure"
473 " \"%s\" (%zu bytes requested)",
474 name, size)));
475 }
476 result->size = size;
477 result->allocated_size = allocated_size;
478 result->location = structPtr;
479 }
480
481 LWLockRelease(ShmemIndexLock);
482
483 Assert(ShmemAddrIsValid(structPtr));
484
485 Assert(structPtr == (void *) CACHELINEALIGN(structPtr));
486
487 return structPtr;
488}
489
490
491/*
492 * Add two Size values, checking for overflow
493 */
494Size
496{
497 Size result;
498
499 if (pg_add_size_overflow(s1, s2, &result))
501 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
502 errmsg("requested shared memory size overflows size_t")));
503 return result;
504}
505
506/*
507 * Multiply two Size values, checking for overflow
508 */
509Size
511{
512 Size result;
513
514 if (pg_mul_size_overflow(s1, s2, &result))
516 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
517 errmsg("requested shared memory size overflows size_t")));
518 return result;
519}
520
521/* SQL SRF showing allocated shared memory */
522Datum
524{
525#define PG_GET_SHMEM_SIZES_COLS 4
526 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
527 HASH_SEQ_STATUS hstat;
528 ShmemIndexEnt *ent;
529 Size named_allocated = 0;
531 bool nulls[PG_GET_SHMEM_SIZES_COLS];
532
533 InitMaterializedSRF(fcinfo, 0);
534
535 LWLockAcquire(ShmemIndexLock, LW_SHARED);
536
537 hash_seq_init(&hstat, ShmemIndex);
538
539 /* output all allocated entries */
540 memset(nulls, 0, sizeof(nulls));
541 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
542 {
543 values[0] = CStringGetTextDatum(ent->key);
544 values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
545 values[2] = Int64GetDatum(ent->size);
546 values[3] = Int64GetDatum(ent->allocated_size);
547 named_allocated += ent->allocated_size;
548
549 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
550 values, nulls);
551 }
552
553 /* output shared memory allocated but not counted via the shmem index */
554 values[0] = CStringGetTextDatum("<anonymous>");
555 nulls[1] = true;
556 values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated);
557 values[3] = values[2];
558 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
559
560 /* output as-of-yet unused shared memory */
561 nulls[0] = true;
563 nulls[1] = false;
565 values[3] = values[2];
566 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
567
568 LWLockRelease(ShmemIndexLock);
569
570 return (Datum) 0;
571}
572
573/*
574 * SQL SRF showing NUMA memory nodes for allocated shared memory
575 *
576 * Compared to pg_get_shmem_allocations(), this function does not return
577 * information about shared anonymous allocations and unused shared memory.
578 */
579Datum
581{
582#define PG_GET_SHMEM_NUMA_SIZES_COLS 3
583 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
584 HASH_SEQ_STATUS hstat;
585 ShmemIndexEnt *ent;
588 Size os_page_size;
589 void **page_ptrs;
590 int *pages_status;
591 uint64 shm_total_page_count,
592 shm_ent_page_count,
593 max_nodes;
594 Size *nodes;
595
596 if (pg_numa_init() == -1)
597 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
598
599 InitMaterializedSRF(fcinfo, 0);
600
601 max_nodes = pg_numa_get_max_node();
602 nodes = palloc(sizeof(Size) * (max_nodes + 1));
603
604 /*
605 * Shared memory allocations can vary in size and may not align with OS
606 * memory page boundaries, while NUMA queries work on pages.
607 *
608 * To correctly map each allocation to NUMA nodes, we need to: 1.
609 * Determine the OS memory page size. 2. Align each allocation's start/end
610 * addresses to page boundaries. 3. Query NUMA node information for all
611 * pages spanning the allocation.
612 */
613 os_page_size = pg_get_shmem_pagesize();
614
615 /*
616 * Allocate memory for page pointers and status based on total shared
617 * memory size. This simplified approach allocates enough space for all
618 * pages in shared memory rather than calculating the exact requirements
619 * for each segment.
620 *
621 * Add 1, because we don't know how exactly the segments align to OS
622 * pages, so the allocation might use one more memory page. In practice
623 * this is not very likely, and moreover we have more entries, each of
624 * them using only fraction of the total pages.
625 */
626 shm_total_page_count = (ShmemSegHdr->totalsize / os_page_size) + 1;
627 page_ptrs = palloc0(sizeof(void *) * shm_total_page_count);
628 pages_status = palloc(sizeof(int) * shm_total_page_count);
629
630 if (firstNumaTouch)
631 elog(DEBUG1, "NUMA: page-faulting shared memory segments for proper NUMA readouts");
632
633 LWLockAcquire(ShmemIndexLock, LW_SHARED);
634
635 hash_seq_init(&hstat, ShmemIndex);
636
637 /* output all allocated entries */
638 memset(nulls, 0, sizeof(nulls));
639 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
640 {
641 int i;
642 char *startptr,
643 *endptr;
644 Size total_len;
645
646 /*
647 * Calculate the range of OS pages used by this segment. The segment
648 * may start / end half-way through a page, we want to count these
649 * pages too. So we align the start/end pointers down/up, and then
650 * calculate the number of pages from that.
651 */
652 startptr = (char *) TYPEALIGN_DOWN(os_page_size, ent->location);
653 endptr = (char *) TYPEALIGN(os_page_size,
654 (char *) ent->location + ent->allocated_size);
655 total_len = (endptr - startptr);
656
657 shm_ent_page_count = total_len / os_page_size;
658
659 /*
660 * If we ever get 0xff (-1) back from kernel inquiry, then we probably
661 * have a bug in mapping buffers to OS pages.
662 */
663 memset(pages_status, 0xff, sizeof(int) * shm_ent_page_count);
664
665 /*
666 * Setup page_ptrs[] with pointers to all OS pages for this segment,
667 * and get the NUMA status using pg_numa_query_pages.
668 *
669 * In order to get reliable results we also need to touch memory
670 * pages, so that inquiry about NUMA memory node doesn't return -2
671 * (ENOENT, which indicates unmapped/unallocated pages).
672 */
673 for (i = 0; i < shm_ent_page_count; i++)
674 {
675 page_ptrs[i] = startptr + (i * os_page_size);
676
677 if (firstNumaTouch)
679
681 }
682
683 if (pg_numa_query_pages(0, shm_ent_page_count, page_ptrs, pages_status) == -1)
684 elog(ERROR, "failed NUMA pages inquiry status: %m");
685
686 /* Count number of NUMA nodes used for this shared memory entry */
687 memset(nodes, 0, sizeof(Size) * (max_nodes + 1));
688
689 for (i = 0; i < shm_ent_page_count; i++)
690 {
691 int s = pages_status[i];
692
693 /* Ensure we are adding only valid index to the array */
694 if (s < 0 || s > max_nodes)
695 {
696 elog(ERROR, "invalid NUMA node id outside of allowed range "
697 "[0, " UINT64_FORMAT "]: %d", max_nodes, s);
698 }
699
700 nodes[s]++;
701 }
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);
711 values[2] = Int64GetDatum(nodes[i] * os_page_size);
712
713 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
714 values, nulls);
715 }
716 }
717
718 LWLockRelease(ShmemIndexLock);
719 firstNumaTouch = false;
720
721 return (Datum) 0;
722}
723
724/*
725 * Determine the memory page size used for the shared memory segment.
726 *
727 * If the shared segment was allocated using huge pages, returns the size of
728 * a huge page. Otherwise returns the size of regular memory page.
729 *
730 * This should be used only after the server is started.
731 */
732Size
734{
735 Size os_page_size;
736#ifdef WIN32
737 SYSTEM_INFO sysinfo;
738
739 GetSystemInfo(&sysinfo);
740 os_page_size = sysinfo.dwPageSize;
741#else
742 os_page_size = sysconf(_SC_PAGESIZE);
743#endif
744
747
749 GetHugePageSize(&os_page_size, NULL);
750
751 return os_page_size;
752}
753
754Datum
756{
758}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define CACHELINEALIGN(LEN)
Definition: c.h:818
#define MAXALIGN(LEN)
Definition: c.h:815
#define TYPEALIGN(ALIGNVAL, LEN)
Definition: c.h:808
int64_t int64
Definition: c.h:540
#define UINT64_FORMAT
Definition: c.h:562
uint64_t uint64
Definition: c.h:544
size_t Size
Definition: c.h:615
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition: c.h:820
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:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#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 PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
bool IsUnderPostmaster
Definition: globals.c:120
int huge_pages_status
Definition: guc_tables.c:582
Assert(PointerIsAligned(start, uint64))
#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
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void * palloc0(Size size)
Definition: mcxt.c:1395
void * palloc(Size size)
Definition: mcxt.c:1365
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
PGDLLIMPORT int pg_numa_get_max_node(void)
Definition: pg_numa.c:136
#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:130
PGDLLIMPORT int pg_numa_init(void)
Definition: pg_numa.c:123
@ HUGE_PAGES_UNKNOWN
Definition: pg_shmem.h:56
@ HUGE_PAGES_ON
Definition: pg_shmem.h:54
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
uint64_t Datum
Definition: postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
char * s1
char * s2
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:276
Datum pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
Definition: shmem.c:580
Datum pg_numa_available(PG_FUNCTION_ARGS)
Definition: shmem.c:755
static void * ShmemBase
Definition: shmem.c:86
Datum pg_get_shmem_allocations(PG_FUNCTION_ARGS)
Definition: shmem.c:523
void InitShmemIndex(void)
Definition: shmem.c:285
static void * ShmemEnd
Definition: shmem.c:88
void InitShmemAccess(PGShmemHeader *seghdr)
Definition: shmem.c:104
Size add_size(Size s1, Size s2)
Definition: shmem.c:495
Size pg_get_shmem_pagesize(void)
Definition: shmem.c:733
#define PG_GET_SHMEM_NUMA_SIZES_COLS
void * ShmemAllocNoError(Size size)
Definition: shmem.c:174
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
void * ShmemAlloc(Size size)
Definition: shmem.c:154
slock_t * ShmemLock
Definition: shmem.c:90
HTAB * ShmemInitHash(const char *name, int64 init_size, int64 max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:334
#define PG_GET_SHMEM_SIZES_COLS
void InitShmemAllocation(void)
Definition: shmem.c:117
static PGShmemHeader * ShmemSegHdr
Definition: shmem.c:84
static void * ShmemAllocRaw(Size size, Size *allocated_size)
Definition: shmem.c:188
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389
static HTAB * ShmemIndex
Definition: shmem.c:93
static void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:240
static bool firstNumaTouch
Definition: shmem.c:96
#define SHMEM_INDEX_SIZE
Definition: shmem.h:53
#define SHMEM_INDEX_KEYSIZE
Definition: shmem.h:51
#define SpinLockInit(lock)
Definition: spin.h:57
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
HashAllocFunc alloc
Definition: hsearch.h:84
Size keysize
Definition: hsearch.h:75
int64 max_dsize
Definition: hsearch.h:73
Size entrysize
Definition: hsearch.h:76
HASHHDR * hctl
Definition: hsearch.h:88
int64 dsize
Definition: hsearch.h:72
Definition: dynahash.c:222
Size freeoffset
Definition: pg_shmem.h:35
void * index
Definition: pg_shmem.h:37
Size totalsize
Definition: pg_shmem.h:34
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
void * location
Definition: shmem.h:59
Size size
Definition: shmem.h:60
Size allocated_size
Definition: shmem.h:61
void GetHugePageSize(Size *hugepagesize, int *mmap_flags)
Definition: sysv_shmem.c:479
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
const char * name