Re: New shared memory hooks proposal (was Re: - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: New shared memory hooks proposal (was Re:
Date
Msg-id 200608011904.k71J4P312093@momjian.us
Whole thread Raw
In response to Re: New shared memory hooks proposal (was Re: pre_load_libraries)  (Marc Munro <marc@bloodnok.com>)
List pgsql-patches
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)))

pgsql-patches by date:

Previous
From: Andrew Dunstan
Date:
Subject: Re: better support of out parameters in plperl
Next
From: Chris Browne
Date:
Subject: Replication Documentation