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)))