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
*** ./src/backend/storage/ipc/ipci.c Sat Jul 15 08:47:17 2006 --- ./new_src/backend/storage/ipc/ipci.c Tue Jul 18 15:26:22 2006 *************** *** 57,62 **** --- 57,63 ---- { PGShmemHeader *seghdr; Size size; + Size size_b4addins; int numSemas; /* *************** *** 93,98 **** --- 94,107 ---- /* 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 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 **** --- 110,125 ---- */ 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); /* *** ./src/backend/storage/ipc/shmem.c Fri Jul 14 07:52:22 2006 --- ./new_src/backend/storage/ipc/shmem.c Tue Jul 18 15:26:22 2006 *************** *** 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(). + * */ #include "postgres.h" *************** *** 86,91 **** --- 95,112 ---- 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. *************** *** 140,146 **** } /* ! * ShmemAlloc -- allocate max-aligned chunk from shared memory * * Assumes ShmemLock and ShmemSegHdr are initialized. * --- 161,255 ---- } /* ! * 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. */ --- 258,287 ---- * 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 --- 300,306 ---- newFree = newStart + size; if (newFree <= shmemseghdr->totalsize) { ! newSpace = (void *) MAKE_PTRFROM((SHMEM_OFFSET) shmemseghdr, newStart); shmemseghdr->freeoffset = newFree; } else *************** *** 193,198 **** --- 317,338 ---- } /* + * 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. *** ./src/backend/storage/lmgr/lwlock.c Fri Jul 14 07:52:23 2006 --- ./new_src/backend/storage/lmgr/lwlock.c Tue Jul 18 15:26:22 2006 *************** *** 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,150 ---- 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; *************** *** 177,182 **** --- 232,240 ---- /* 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; } *************** *** 245,250 **** --- 303,314 ---- LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int)); LWLockCounter[0] = (int) FirstLockMgrLock + NUM_LOCK_PARTITIONS; LWLockCounter[1] = numLocks; + + /* + * Allocate LWLocks for those add-ins that have explicitly requested + * them. + */ + AssignAddinLWLocks(); } *** ./src/include/storage/lwlock.h Sun May 7 17:00:17 2006 --- ./new_src/include/storage/lwlock.h Tue Jul 18 15:22:09 2006 *************** *** 76,79 **** --- 76,81 ---- extern Size LWLockShmemSize(void); extern void CreateLWLocks(void); + extern void RegisterAddinLWLock(LWLockId *lock); + #endif /* LWLOCK_H */ *** ./src/include/storage/pg_shmem.h Sun Mar 5 07:58:59 2006 --- ./new_src/include/storage/pg_shmem.h Tue Jul 18 15:14:05 2006 *************** *** 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 */ *** ./src/include/storage/shmem.h Sun Mar 5 07:59:00 2006 --- ./new_src/include/storage/shmem.h Tue Jul 18 12:49:09 2006 *************** *** 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)))
signature.asc
Description: This is a digitally signed message part