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
