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

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to