Re: New shared memory hooks proposal (was Re: - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: New shared memory hooks proposal (was Re: |
Date | |
Msg-id | 200608011904.k71J4P312093@momjian.us Whole thread Raw |
In response to | Re: New shared memory hooks proposal (was Re: pre_load_libraries) (Marc Munro <marc@bloodnok.com>) |
List | pgsql-patches |
I updated the style of your patch, and added a little to your comment block about how to use this capability. I don't think any additional documentation is necessary. Thanks. --------------------------------------------------------------------------- Marc Munro wrote: -- Start of PGP signed section. > The attached patch provides add-ins with the means to register for > shared memory and LWLocks. This greatly improves the ease with which > shared memory may be used from add-ins, while keeping the accounting and > management for that shared memory separate. > > Specifically it adds named add-in shared memory contexts. From these, > memory can be allocated without affecting the memory available in other > contexts. > > Usage is as follows: > from add-in functions called from preload_libraries, you may call > RegisterAddinContext(const * name, size_t size) > to register a new (logical) shared memory segment. > > and > RegisterAddinLWLock(LWLockid *lock_ptr); > to request that a LWLock be allocated, placed into *lock_ptr. > > The actual creation of the shared memory segment and lwlocks is > performed later as part of shared memory initialisation. > > To allocate shared memory from a named context you would use > ShmemAllocFromContext(size_t size, const char *name); > > To reset a shared memory context back to its original unused state (from > which new allocations may be performed), you may use > ShmemResetContext(const char *name); > > This works for me (for Veil) and make check runs fine. > > I have not included any documentation updates in the patch as I'm not > sure where such API changes should be documented. > > All comments, questions and suggestions are welcomed. > > __ > Marc [ Attachment, skipping... ] -- End of PGP section, PGP failed! -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. + Index: src/backend/storage/ipc/ipci.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v retrieving revision 1.86 diff -c -c -r1.86 ipci.c *** src/backend/storage/ipc/ipci.c 15 Jul 2006 15:47:17 -0000 1.86 --- src/backend/storage/ipc/ipci.c 1 Aug 2006 19:01:09 -0000 *************** *** 57,62 **** --- 57,63 ---- { PGShmemHeader *seghdr; Size size; + Size size_b4addins; int numSemas; /* *************** *** 93,98 **** --- 94,108 ---- /* might as well round it off to a multiple of a typical page size */ size = add_size(size, 8192 - (size % 8192)); + /* + * The shared memory for add-ins is treated as a separate + * segment, but in reality it is not. + */ + size_b4addins = size; + size = add_size(size, AddinShmemSize()); + /* round it off again */ + size = add_size(size, 8192 - (size % 8192)); + elog(DEBUG3, "invoking IpcMemoryCreate(size=%lu)", (unsigned long) size); *************** *** 101,106 **** --- 111,126 ---- */ seghdr = PGSharedMemoryCreate(size, makePrivate, port); + /* + * Modify hdr to show segment size before add-ins + */ + seghdr->totalsize = size_b4addins; + + /* + * Set up segment header sections in each Addin context + */ + InitAddinContexts((void *) ((char *) seghdr + size_b4addins)); + InitShmemAccess(seghdr); /* Index: src/backend/storage/ipc/shmem.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v retrieving revision 1.94 diff -c -c -r1.94 shmem.c *** src/backend/storage/ipc/shmem.c 22 Jul 2006 23:04:39 -0000 1.94 --- src/backend/storage/ipc/shmem.c 1 Aug 2006 19:01:09 -0000 *************** *** 61,66 **** --- 61,75 ---- * cannot be redistributed to other tables. We could build a simple * hash bucket garbage collector if need be. Right now, it seems * unnecessary. + * + * (e) Add-ins can request their own logical shared memory segments + * by calling RegisterAddinContext() from the preload-libraries hook. + * Each call establishes a uniquely named add-in shared memopry + * context which will be set up as part of postgres intialisation. + * Memory can be allocated from these contexts using + * ShmemAllocFromContext(), and can be reset to its initial condition + * using ShmemResetContext(). Also, RegisterAddinLWLock(LWLockid *lock_ptr) + * can be used to request that a LWLock be allocated, placed into *lock_ptr. */ #include "postgres.h" *************** *** 86,91 **** --- 95,113 ---- static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */ + /* Structures and globals for managing add-in shared memory contexts */ + typedef struct context + { + char *name; + Size size; + PGShmemHeader *seg_hdr; + struct context *next; + } ContextNode; + + static ContextNode *addin_contexts = NULL; + static Size addin_contexts_size = 0; + + /* * InitShmemAccess() --- set up basic pointers to shared memory. *************** *** 135,146 **** * (This doesn't really belong here, but not worth moving.) */ ShmemVariableCache = (VariableCache) ! ShmemAlloc(sizeof(*ShmemVariableCache)); memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache)); } /* ! * ShmemAlloc -- allocate max-aligned chunk from shared memory * * Assumes ShmemLock and ShmemSegHdr are initialized. * --- 157,260 ---- * (This doesn't really belong here, but not worth moving.) */ ShmemVariableCache = (VariableCache) ! ShmemAlloc(sizeof(*ShmemVariableCache)); memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache)); } /* ! * RegisterAddinContext -- Register the requirement for a named shared ! * memory context. ! */ ! void ! RegisterAddinContext(const char *name, Size size) ! { ! char *newstr = malloc(strlen(name) + 1); ! ContextNode *node = malloc(sizeof(ContextNode)); ! ! strcpy(newstr, name); ! node->name = newstr; ! ! /* Round up to typical page size */ ! node->size = add_size(size, 8192 - (size % 8192)); ! node->next = addin_contexts; ! ! addin_contexts = node; ! addin_contexts_size = add_size(addin_contexts_size, node->size); ! } ! ! ! /* ! * ContextFromName -- Return the ContextNode for the given named ! * context, or NULL if not found. ! */ ! static ContextNode * ! ContextFromName(const char *name) ! { ! ContextNode *context = addin_contexts; ! ! while (context) ! { ! if (strcmp(name, context->name) == 0) ! return context; ! context = context->next; ! } ! return NULL; ! } ! ! /* ! * InitAddinContexts -- Initialise the registered addin shared memory ! * contexts. ! */ ! void ! InitAddinContexts(void *start) ! { ! PGShmemHeader *next_segment = (PGShmemHeader *) start; ! ContextNode *context = addin_contexts; ! ! while (context) ! { ! context->seg_hdr = next_segment; ! ! next_segment->totalsize = context->size; ! next_segment->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); ! ! next_segment = (PGShmemHeader *) ! ((char *) next_segment + context->size); ! context = context->next; ! } ! } ! ! /* ! * ShmemResetContext -- Re-initialise the named addin shared memory context. ! */ ! void ! ShmemResetContext(const char *name) ! { ! PGShmemHeader *segment; ! ContextNode *context = ContextFromName(name); ! ! if (!context) ! ereport(ERROR, ! (errcode(ERRCODE_INTERNAL_ERROR), ! errmsg("cannot reset unknown shared memory context %s", ! name))); ! ! segment = context->seg_hdr; ! segment->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); ! } ! ! /* ! * AddinShmemSize -- Report how much shared memory has been registered ! * for add-ins. ! */ ! Size ! AddinShmemSize(void) ! { ! return addin_contexts_size; ! } ! ! /* ! * ShmemAllocFromContext -- allocate max-aligned chunk from shared memory * * Assumes ShmemLock and ShmemSegHdr are initialized. * *************** *** 149,163 **** * to be compatible with malloc(). */ void * ! ShmemAlloc(Size size) { ! Size newStart; ! Size newFree; ! void *newSpace; /* use volatile pointer to prevent code rearrangement */ volatile PGShmemHeader *shmemseghdr = ShmemSegHdr; /* * ensure all space is adequately aligned. */ --- 263,292 ---- * to be compatible with malloc(). */ void * ! ShmemAllocFromContext(Size size, const char *context_name) { ! Size newStart; ! Size newFree; ! void *newSpace; ! ContextNode *context; /* use volatile pointer to prevent code rearrangement */ volatile PGShmemHeader *shmemseghdr = ShmemSegHdr; + /* + * if context_name is provided, allocate from the named context + */ + if (context_name) + { + context = ContextFromName(context_name); + if (!context) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("cannot reset unknown shared memory context %s", + context_name))); + shmemseghdr = context->seg_hdr; + } + /* * ensure all space is adequately aligned. */ *************** *** 176,182 **** newFree = newStart + size; if (newFree <= shmemseghdr->totalsize) { ! newSpace = (void *) MAKE_PTR(newStart); shmemseghdr->freeoffset = newFree; } else --- 305,311 ---- newFree = newStart + size; if (newFree <= shmemseghdr->totalsize) { ! newSpace = (void *) MAKE_PTRFROM((SHMEM_OFFSET) shmemseghdr, newStart); shmemseghdr->freeoffset = newFree; } else *************** *** 193,198 **** --- 322,343 ---- } /* + * ShmemAlloc -- allocate max-aligned chunk from shared memory + * + * Assumes ShmemLock and ShmemSegHdr are initialized. + * + * Returns: real pointer to memory or NULL if we are out + * of space. Has to return a real pointer in order + * to be compatible with malloc(). + */ + + void * + ShmemAlloc(Size size) + { + return ShmemAllocFromContext(size, NULL); + } + + /* * ShmemIsValid -- test if an offset refers to valid shared memory * * Returns TRUE if the pointer is valid. Index: src/backend/storage/lmgr/lwlock.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/storage/lmgr/lwlock.c,v retrieving revision 1.42 diff -c -c -r1.42 lwlock.c *** src/backend/storage/lmgr/lwlock.c 24 Jul 2006 16:32:45 -0000 1.42 --- src/backend/storage/lmgr/lwlock.c 1 Aug 2006 19:01:09 -0000 *************** *** 29,34 **** --- 29,38 ---- #include "storage/spin.h" + static int NumAddinLWLocks(void); + static void AssignAddinLWLocks(void); + + /* We use the ShmemLock spinlock to protect LWLockAssign */ extern slock_t *ShmemLock; *************** *** 90,95 **** --- 94,155 ---- static int *block_counts; #endif + /* + * Structures and globals to allow add-ins to register for their own + * lwlocks from the preload-libraries hook. + */ + typedef struct LWLockNode + { + LWLockId *lock; + struct LWLockNode *next; + } LWLockNode; + + static LWLockNode *addin_locks = NULL; + static int num_addin_locks = 0; + + + /* + * RegisterAddinLWLock() --- Allow an andd-in to request a LWLock + * from the preload-libraries hook. + */ + void + RegisterAddinLWLock(LWLockId *lock) + { + LWLockNode *locknode = malloc(sizeof(LWLockNode)); + + locknode->next = addin_locks; + locknode->lock = lock; + + addin_locks = locknode; + num_addin_locks++; + } + + /* + * NumAddinLWLocks() --- Return the number of LWLocks requested by add-ins. + */ + int + NumAddinLWLocks() + { + return num_addin_locks; + } + + /* + * AssignAddinLWLocks() --- Assign LWLocks previously requested by add-ins. + */ + void + AssignAddinLWLocks() + { + LWLockNode *node = addin_locks; + + while (node) + { + *(node->lock) = LWLockAssign(); + node = node->next; + } + } + + + #ifdef LOCK_DEBUG bool Trace_lwlocks = false; *************** *** 174,179 **** --- 234,242 ---- /* Leave a few extra for use by user-defined modules. */ numLocks += NUM_USER_DEFINED_LWLOCKS; + /* Add the number that have been explicitly requested by add-ins. */ + numLocks += NumAddinLWLocks(); + return numLocks; } *************** *** 241,246 **** --- 304,315 ---- LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int)); LWLockCounter[0] = (int) NumFixedLWLocks; LWLockCounter[1] = numLocks; + + /* + * Allocate LWLocks for those add-ins that have explicitly requested + * them. + */ + AssignAddinLWLocks(); } Index: src/include/storage/lwlock.h =================================================================== RCS file: /cvsroot/pgsql/src/include/storage/lwlock.h,v retrieving revision 1.30 diff -c -c -r1.30 lwlock.h *** src/include/storage/lwlock.h 23 Jul 2006 23:08:46 -0000 1.30 --- src/include/storage/lwlock.h 1 Aug 2006 19:01:10 -0000 *************** *** 92,95 **** --- 92,97 ---- extern Size LWLockShmemSize(void); extern void CreateLWLocks(void); + extern void RegisterAddinLWLock(LWLockId *lock); + #endif /* LWLOCK_H */ Index: src/include/storage/pg_shmem.h =================================================================== RCS file: /cvsroot/pgsql/src/include/storage/pg_shmem.h,v retrieving revision 1.18 diff -c -c -r1.18 pg_shmem.h *** src/include/storage/pg_shmem.h 5 Mar 2006 15:58:59 -0000 1.18 --- src/include/storage/pg_shmem.h 1 Aug 2006 19:01:10 -0000 *************** *** 51,54 **** --- 51,61 ---- extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); extern void PGSharedMemoryDetach(void); + + extern void RegisterAddinContext(const char *name, Size size); + extern Size AddinShmemSize(void); + extern void InitAddinContexts(void * start); + extern void *ShmemAllocFromContext(Size size, const char *name); + extern void ShmemResetContext(const char *name); + #endif /* PG_SHMEM_H */ Index: src/include/storage/shmem.h =================================================================== RCS file: /cvsroot/pgsql/src/include/storage/shmem.h,v retrieving revision 1.47 diff -c -c -r1.47 shmem.h *** src/include/storage/shmem.h 5 Mar 2006 15:59:00 -0000 1.47 --- src/include/storage/shmem.h 1 Aug 2006 19:01:10 -0000 *************** *** 38,43 **** --- 38,48 ---- extern DLLIMPORT SHMEM_OFFSET ShmemBase; + /* coerce an offset into a pointer in a specified address space. This + * macro (only) is not confined to the primary shared memory region */ + #define MAKE_PTRFROM(base,xx_offs)\ + (base+((unsigned long)(xx_offs))) + /* coerce an offset into a pointer in this process's address space */ #define MAKE_PTR(xx_offs)\ (ShmemBase+((unsigned long)(xx_offs)))
pgsql-patches by date: