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-2020, 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 "access/transam.h"
69 #include "fmgr.h"
70 #include "funcapi.h"
71 #include "miscadmin.h"
72 #include "storage/lwlock.h"
73 #include "storage/pg_shmem.h"
74 #include "storage/shmem.h"
75 #include "storage/spin.h"
76 #include "utils/builtins.h"
77 
78 static void *ShmemAllocRaw(Size size, Size *allocated_size);
79 
80 /* shared memory global variables */
81 
82 static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
83 
84 static void *ShmemBase; /* start address of shared memory */
85 
86 static void *ShmemEnd; /* end+1 address of shared memory */
87 
88 slock_t *ShmemLock; /* spinlock for shared memory and LWLock
89  * allocation */
90 
91 static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
92 
93 
94 /*
95  * InitShmemAccess() --- set up basic pointers to shared memory.
96  *
97  * Note: the argument should be declared "PGShmemHeader *seghdr",
98  * but we use void to avoid having to include ipc.h in shmem.h.
99  */
100 void
101 InitShmemAccess(void *seghdr)
102 {
103  PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;
104 
105  ShmemSegHdr = shmhdr;
106  ShmemBase = (void *) shmhdr;
107  ShmemEnd = (char *) ShmemBase + shmhdr->totalsize;
108 }
109 
110 /*
111  * InitShmemAllocation() --- set up shared-memory space allocation.
112  *
113  * This should be called only in the postmaster or a standalone backend.
114  */
115 void
117 {
118  PGShmemHeader *shmhdr = ShmemSegHdr;
119  char *aligned;
120 
121  Assert(shmhdr != NULL);
122 
123  /*
124  * Initialize the spinlock used by ShmemAlloc. We must use
125  * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet.
126  */
128 
130 
131  /*
132  * Allocations after this point should go through ShmemAlloc, which
133  * expects to allocate everything on cache line boundaries. Make sure the
134  * first allocation begins on a cache line boundary.
135  */
136  aligned = (char *)
137  (CACHELINEALIGN((((char *) shmhdr) + shmhdr->freeoffset)));
138  shmhdr->freeoffset = aligned - (char *) shmhdr;
139 
140  /* ShmemIndex can't be set up yet (need LWLocks first) */
141  shmhdr->index = NULL;
142  ShmemIndex = (HTAB *) NULL;
143 
144  /*
145  * Initialize ShmemVariableCache for transaction manager. (This doesn't
146  * really belong here, but not worth moving.)
147  */
149  ShmemAlloc(sizeof(*ShmemVariableCache));
150  memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
151 }
152 
153 /*
154  * ShmemAlloc -- allocate max-aligned chunk from shared memory
155  *
156  * Throws error if request cannot be satisfied.
157  *
158  * Assumes ShmemLock and ShmemSegHdr are initialized.
159  */
160 void *
162 {
163  void *newSpace;
164  Size allocated_size;
165 
166  newSpace = ShmemAllocRaw(size, &allocated_size);
167  if (!newSpace)
168  ereport(ERROR,
169  (errcode(ERRCODE_OUT_OF_MEMORY),
170  errmsg("out of shared memory (%zu bytes requested)",
171  size)));
172  return newSpace;
173 }
174 
175 /*
176  * ShmemAllocNoError -- allocate max-aligned chunk from shared memory
177  *
178  * As ShmemAlloc, but returns NULL if out of space, rather than erroring.
179  */
180 void *
182 {
183  Size allocated_size;
184 
185  return ShmemAllocRaw(size, &allocated_size);
186 }
187 
188 /*
189  * ShmemAllocRaw -- allocate align chunk and return allocated size
190  *
191  * Also sets *allocated_size to the number of bytes allocated, which will
192  * be equal to the number requested plus any padding we choose to add.
193  */
194 static void *
195 ShmemAllocRaw(Size size, Size *allocated_size)
196 {
197  Size newStart;
198  Size newFree;
199  void *newSpace;
200 
201  /*
202  * Ensure all space is adequately aligned. We used to only MAXALIGN this
203  * space but experience has proved that on modern systems that is not good
204  * enough. Many parts of the system are very sensitive to critical data
205  * structures getting split across cache line boundaries. To avoid that,
206  * attempt to align the beginning of the allocation to a cache line
207  * boundary. The calling code will still need to be careful about how it
208  * uses the allocated space - e.g. by padding each element in an array of
209  * structures out to a power-of-two size - but without this, even that
210  * won't be sufficient.
211  */
212  size = CACHELINEALIGN(size);
213  *allocated_size = size;
214 
215  Assert(ShmemSegHdr != NULL);
216 
218 
219  newStart = ShmemSegHdr->freeoffset;
220 
221  newFree = newStart + size;
222  if (newFree <= ShmemSegHdr->totalsize)
223  {
224  newSpace = (void *) ((char *) ShmemBase + newStart);
225  ShmemSegHdr->freeoffset = newFree;
226  }
227  else
228  newSpace = NULL;
229 
231 
232  /* note this assert is okay with newSpace == NULL */
233  Assert(newSpace == (void *) CACHELINEALIGN(newSpace));
234 
235  return newSpace;
236 }
237 
238 /*
239  * ShmemAllocUnlocked -- allocate max-aligned chunk from shared memory
240  *
241  * Allocate space without locking ShmemLock. This should be used for,
242  * and only for, allocations that must happen before ShmemLock is ready.
243  *
244  * We consider maxalign, rather than cachealign, sufficient here.
245  */
246 void *
248 {
249  Size newStart;
250  Size newFree;
251  void *newSpace;
252 
253  /*
254  * Ensure allocated space is adequately aligned.
255  */
256  size = MAXALIGN(size);
257 
258  Assert(ShmemSegHdr != NULL);
259 
260  newStart = ShmemSegHdr->freeoffset;
261 
262  newFree = newStart + size;
263  if (newFree > ShmemSegHdr->totalsize)
264  ereport(ERROR,
265  (errcode(ERRCODE_OUT_OF_MEMORY),
266  errmsg("out of shared memory (%zu bytes requested)",
267  size)));
268  ShmemSegHdr->freeoffset = newFree;
269 
270  newSpace = (void *) ((char *) ShmemBase + newStart);
271 
272  Assert(newSpace == (void *) MAXALIGN(newSpace));
273 
274  return newSpace;
275 }
276 
277 /*
278  * ShmemAddrIsValid -- test if an address refers to shared memory
279  *
280  * Returns true if the pointer points within the shared memory segment.
281  */
282 bool
283 ShmemAddrIsValid(const void *addr)
284 {
285  return (addr >= ShmemBase) && (addr < ShmemEnd);
286 }
287 
288 /*
289  * InitShmemIndex() --- set up or attach to shmem index table.
290  */
291 void
293 {
294  HASHCTL info;
295  int hash_flags;
296 
297  /*
298  * Create the shared memory shmem index.
299  *
300  * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
301  * hashtable to exist already, we have a bit of a circularity problem in
302  * initializing the ShmemIndex itself. The special "ShmemIndex" hash
303  * table name will tell ShmemInitStruct to fake it.
304  */
306  info.entrysize = sizeof(ShmemIndexEnt);
307  hash_flags = HASH_ELEM;
308 
309  ShmemIndex = ShmemInitHash("ShmemIndex",
311  &info, hash_flags);
312 }
313 
314 /*
315  * ShmemInitHash -- Create and initialize, or attach to, a
316  * shared memory hash table.
317  *
318  * We assume caller is doing some kind of synchronization
319  * so that two processes don't try to create/initialize the same
320  * table at once. (In practice, all creations are done in the postmaster
321  * process; child processes should always be attaching to existing tables.)
322  *
323  * max_size is the estimated maximum number of hashtable entries. This is
324  * not a hard limit, but the access efficiency will degrade if it is
325  * exceeded substantially (since it's used to compute directory size and
326  * the hash table buckets will get overfull).
327  *
328  * init_size is the number of hashtable entries to preallocate. For a table
329  * whose maximum size is certain, this should be equal to max_size; that
330  * ensures that no run-time out-of-shared-memory failures can occur.
331  *
332  * Note: before Postgres 9.0, this function returned NULL for some failure
333  * cases. Now, it always throws error instead, so callers need not check
334  * for NULL.
335  */
336 HTAB *
337 ShmemInitHash(const char *name, /* table string name for shmem index */
338  long init_size, /* initial table size */
339  long max_size, /* max size of the table */
340  HASHCTL *infoP, /* info about key and bucket size */
341  int hash_flags) /* info about infoP */
342 {
343  bool found;
344  void *location;
345 
346  /*
347  * Hash tables allocated in shared memory have a fixed directory; it can't
348  * grow or other backends wouldn't be able to find it. So, make sure we
349  * make it big enough to start with.
350  *
351  * The shared memory allocator must be specified too.
352  */
353  infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
354  infoP->alloc = ShmemAllocNoError;
355  hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
356 
357  /* look it up in the shmem index */
358  location = ShmemInitStruct(name,
359  hash_get_shared_size(infoP, hash_flags),
360  &found);
361 
362  /*
363  * if it already exists, attach to it rather than allocate and initialize
364  * new space
365  */
366  if (found)
367  hash_flags |= HASH_ATTACH;
368 
369  /* Pass location of hashtable header to hash_create */
370  infoP->hctl = (HASHHDR *) location;
371 
372  return hash_create(name, init_size, infoP, hash_flags);
373 }
374 
375 /*
376  * ShmemInitStruct -- Create/attach to a structure in shared memory.
377  *
378  * This is called during initialization to find or allocate
379  * a data structure in shared memory. If no other process
380  * has created the structure, this routine allocates space
381  * for it. If it exists already, a pointer to the existing
382  * structure is returned.
383  *
384  * Returns: pointer to the object. *foundPtr is set true if the object was
385  * already in the shmem index (hence, already initialized).
386  *
387  * Note: before Postgres 9.0, this function returned NULL for some failure
388  * cases. Now, it always throws error instead, so callers need not check
389  * for NULL.
390  */
391 void *
392 ShmemInitStruct(const char *name, Size size, bool *foundPtr)
393 {
394  ShmemIndexEnt *result;
395  void *structPtr;
396 
397  LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
398 
399  if (!ShmemIndex)
400  {
401  PGShmemHeader *shmemseghdr = ShmemSegHdr;
402 
403  /* Must be trying to create/attach to ShmemIndex itself */
404  Assert(strcmp(name, "ShmemIndex") == 0);
405 
406  if (IsUnderPostmaster)
407  {
408  /* Must be initializing a (non-standalone) backend */
409  Assert(shmemseghdr->index != NULL);
410  structPtr = shmemseghdr->index;
411  *foundPtr = true;
412  }
413  else
414  {
415  /*
416  * If the shmem index doesn't exist, we are bootstrapping: we must
417  * be trying to init the shmem index itself.
418  *
419  * Notice that the ShmemIndexLock is released before the shmem
420  * index has been initialized. This should be OK because no other
421  * process can be accessing shared memory yet.
422  */
423  Assert(shmemseghdr->index == NULL);
424  structPtr = ShmemAlloc(size);
425  shmemseghdr->index = structPtr;
426  *foundPtr = false;
427  }
428  LWLockRelease(ShmemIndexLock);
429  return structPtr;
430  }
431 
432  /* look it up in the shmem index */
433  result = (ShmemIndexEnt *)
434  hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr);
435 
436  if (!result)
437  {
438  LWLockRelease(ShmemIndexLock);
439  ereport(ERROR,
440  (errcode(ERRCODE_OUT_OF_MEMORY),
441  errmsg("could not create ShmemIndex entry for data structure \"%s\"",
442  name)));
443  }
444 
445  if (*foundPtr)
446  {
447  /*
448  * Structure is in the shmem index so someone else has allocated it
449  * already. The size better be the same as the size we are trying to
450  * initialize to, or there is a name conflict (or worse).
451  */
452  if (result->size != size)
453  {
454  LWLockRelease(ShmemIndexLock);
455  ereport(ERROR,
456  (errmsg("ShmemIndex entry size is wrong for data structure"
457  " \"%s\": expected %zu, actual %zu",
458  name, size, result->size)));
459  }
460  structPtr = result->location;
461  }
462  else
463  {
464  Size allocated_size;
465 
466  /* It isn't in the table yet. allocate and initialize it */
467  structPtr = ShmemAllocRaw(size, &allocated_size);
468  if (structPtr == NULL)
469  {
470  /* out of memory; remove the failed ShmemIndex entry */
471  hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
472  LWLockRelease(ShmemIndexLock);
473  ereport(ERROR,
474  (errcode(ERRCODE_OUT_OF_MEMORY),
475  errmsg("not enough shared memory for data structure"
476  " \"%s\" (%zu bytes requested)",
477  name, size)));
478  }
479  result->size = size;
480  result->allocated_size = allocated_size;
481  result->location = structPtr;
482  }
483 
484  LWLockRelease(ShmemIndexLock);
485 
486  Assert(ShmemAddrIsValid(structPtr));
487 
488  Assert(structPtr == (void *) CACHELINEALIGN(structPtr));
489 
490  return structPtr;
491 }
492 
493 
494 /*
495  * Add two Size values, checking for overflow
496  */
497 Size
499 {
500  Size result;
501 
502  result = s1 + s2;
503  /* We are assuming Size is an unsigned type here... */
504  if (result < s1 || result < s2)
505  ereport(ERROR,
506  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
507  errmsg("requested shared memory size overflows size_t")));
508  return result;
509 }
510 
511 /*
512  * Multiply two Size values, checking for overflow
513  */
514 Size
516 {
517  Size result;
518 
519  if (s1 == 0 || s2 == 0)
520  return 0;
521  result = s1 * s2;
522  /* We are assuming Size is an unsigned type here... */
523  if (result / s2 != s1)
524  ereport(ERROR,
525  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
526  errmsg("requested shared memory size overflows size_t")));
527  return result;
528 }
529 
530 /* SQL SRF showing allocated shared memory */
531 Datum
533 {
534 #define PG_GET_SHMEM_SIZES_COLS 4
535  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
536  TupleDesc tupdesc;
537  Tuplestorestate *tupstore;
538  MemoryContext per_query_ctx;
539  MemoryContext oldcontext;
540  HASH_SEQ_STATUS hstat;
541  ShmemIndexEnt *ent;
542  Size named_allocated = 0;
544  bool nulls[PG_GET_SHMEM_SIZES_COLS];
545 
546  /* check to see if caller supports us returning a tuplestore */
547  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
548  ereport(ERROR,
549  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
550  errmsg("set-valued function called in context that cannot accept a set")));
551  if (!(rsinfo->allowedModes & SFRM_Materialize))
552  ereport(ERROR,
553  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
554  errmsg("materialize mode required, but it is not allowed in this context")));
555 
556  /* Build a tuple descriptor for our result type */
557  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
558  elog(ERROR, "return type must be a row type");
559 
560  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
561  oldcontext = MemoryContextSwitchTo(per_query_ctx);
562 
563  tupstore = tuplestore_begin_heap(true, false, work_mem);
564  rsinfo->returnMode = SFRM_Materialize;
565  rsinfo->setResult = tupstore;
566  rsinfo->setDesc = tupdesc;
567 
568  MemoryContextSwitchTo(oldcontext);
569 
570  LWLockAcquire(ShmemIndexLock, LW_SHARED);
571 
572  hash_seq_init(&hstat, ShmemIndex);
573 
574  /* output all allocated entries */
575  memset(nulls, 0, sizeof(nulls));
576  while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
577  {
578  values[0] = CStringGetTextDatum(ent->key);
579  values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
580  values[2] = Int64GetDatum(ent->size);
581  values[3] = Int64GetDatum(ent->allocated_size);
582  named_allocated += ent->allocated_size;
583 
584  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
585  }
586 
587  /* output shared memory allocated but not counted via the shmem index */
588  values[0] = CStringGetTextDatum("<anonymous>");
589  nulls[1] = true;
590  values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated);
591  values[3] = values[2];
592  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
593 
594  /* output as-of-yet unused shared memory */
595  nulls[0] = true;
596  values[1] = Int64GetDatum(ShmemSegHdr->freeoffset);
597  nulls[1] = false;
598  values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset);
599  values[3] = values[2];
600  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
601 
602  LWLockRelease(ShmemIndexLock);
603 
604  tuplestore_donestoring(tupstore);
605 
606  return (Datum) 0;
607 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
int slock_t
Definition: s_lock.h:934
VariableCacheData * VariableCache
Definition: transam.h:192
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static PGShmemHeader * ShmemSegHdr
Definition: shmem.c:82
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:196
#define SHMEM_INDEX_SIZE
Definition: shmem.h:55
#define HASH_ELEM
Definition: hsearch.h:87
void InitShmemAccess(void *seghdr)
Definition: shmem.c:101
#define SpinLockInit(lock)
Definition: spin.h:60
#define PG_GET_SHMEM_SIZES_COLS
Size size
Definition: shmem.h:62
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:73
int errcode(int sqlerrcode)
Definition: elog.c:608
void * ShmemAllocNoError(Size size)
Definition: shmem.c:181
void * ShmemAlloc(Size size)
Definition: shmem.c:161
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static void * ShmemBase
Definition: shmem.c:84
#define HASH_SHARED_MEM
Definition: hsearch.h:94
long dsize
Definition: hsearch.h:69
#define HASH_ATTACH
Definition: hsearch.h:95
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
static HTAB * ShmemIndex
Definition: shmem.c:91
#define SpinLockAcquire(lock)
Definition: spin.h:62
Definition: dynahash.c:208
long max_dsize
Definition: hsearch.h:70
#define ERROR
Definition: elog.h:43
char * s1
void * location
Definition: shmem.h:61
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
HashAllocFunc alloc
Definition: hsearch.h:77
static void * ShmemEnd
Definition: shmem.c:86
bool IsUnderPostmaster
Definition: globals.c:109
VariableCache ShmemVariableCache
Definition: varsup.c:34
Datum pg_get_shmem_allocations(PG_FUNCTION_ARGS)
Definition: shmem.c:532
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
#define ereport(elevel, rest)
Definition: elog.h:141
static void * ShmemAllocRaw(Size size, Size *allocated_size)
Definition: shmem.c:195
#define SpinLockRelease(lock)
Definition: spin.h:64
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
Size totalsize
Definition: pg_shmem.h:34
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515
char * s2
uintptr_t Datum
Definition: postgres.h:367
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:247
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
Size keysize
Definition: hsearch.h:72
int work_mem
Definition: globals.c:121
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:283
int allowedModes
Definition: execnodes.h:302
long hash_select_dirsize(long num_entries)
Definition: dynahash.c:779
SetFunctionReturnMode returnMode
Definition: execnodes.h:304
#define Assert(condition)
Definition: c.h:739
#define CACHELINEALIGN(LEN)
Definition: c.h:695
Size freeoffset
Definition: pg_shmem.h:35
size_t Size
Definition: c.h:467
Size allocated_size
Definition: shmem.h:63
#define SHMEM_INDEX_KEYSIZE
Definition: shmem.h:53
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
#define MAXALIGN(LEN)
Definition: c.h:692
Size hash_get_shared_size(HASHCTL *info, int flags)
Definition: dynahash.c:803
HASHHDR * hctl
Definition: hsearch.h:79
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:230
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
const char * name
Definition: encode.c:521
Tuplestorestate * setResult
Definition: execnodes.h:307
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ExprContext * econtext
Definition: execnodes.h:300
TupleDesc setDesc
Definition: execnodes.h:308
#define HASH_DIRSIZE
Definition: hsearch.h:85
slock_t * ShmemLock
Definition: shmem.c:88
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
#define HASH_ALLOC
Definition: hsearch.h:92
#define CStringGetTextDatum(s)
Definition: builtins.h:83
void InitShmemIndex(void)
Definition: shmem.c:292
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
void * index
Definition: pg_shmem.h:37
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:337
void InitShmemAllocation(void)
Definition: shmem.c:116