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   [EMAIL PROTECTED]
  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)))
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to