Re: dynamic shared memory and locks - Mailing list pgsql-hackers

From Robert Haas
Subject Re: dynamic shared memory and locks
Date
Msg-id CA+TgmoZNr9ZgMr9gaSzwJgBZf9_3o2PpaRny_7z8JxG+GatEbA@mail.gmail.com
Whole thread Raw
In response to Re: dynamic shared memory and locks  (Robert Haas <robertmhaas@gmail.com>)
Responses Re: dynamic shared memory and locks  (Kohei KaiGai <kaigai@kaigai.gr.jp>)
List pgsql-hackers
On Tue, Jan 21, 2014 at 11:37 AM, Robert Haas <robertmhaas@gmail.com> wrote:
> One idea I just had is to improve the dsm_toc module so that it can
> optionally set up a tranche of lwlocks for you, and provide some
> analogues of RequestAddinLWLocks and LWLockAssign for that case.  That
> would probably make this quite a bit simpler to use, at least for
> people using it with dynamic shared memory.  But I think that's a
> separate patch.

I played with this a bit today and it doesn't actually seem to
simplify things very much.  The backend that creates the DSM needs to
do this:
   lwlocks = shm_toc_allocate(toc, sizeof(LWLockPadded) * nlwlocks);   for (i = 0; i < nlwlocks; ++i)
LWLockInitialize(&lwlocks[i].lock,tranche_id);
 

Since that's all of three lines, encapsulating it doesn't look all
that helpful.  Then each backend needs to do something like this:
   static LWLockTranche mytranche;   mytranche.name = "some descriptive module name";   mytranche.array_base = lwlocks;
 mytranche.array_stride = sizeof(LWLockPadded);   LWLockRegisterTranche(tranche_id, &mytranche);
 

That's not a lot of code either, and there's no obvious way to reduce
it much by hooking into shm_toc.

I thought maybe we needed some cleanup when the dynamic shared memory
segment is unmapped, but looks like we really don't.  One can do
something like LWLockRegisterTranche(tranche_id, NULL) for debugging
clarity, but it isn't strictly needed; one can release all lwlocks
from the tranche or assert that none are held, but that should really
only be a problem if the user does something like
LWLockAcquire(lock_in_the_segment); dsm_detach(seg), because error
recovery starts by releasing *all* lwlocks.  And if the user does it
explicitly, I'm kinda OK with that just seg faulting.  After all, the
user could equally well have done dsm_detach(seg);
LWLockAcquire(lock_in_the_segment) and there's no way at all to
cross-check for that sort of mistake.

I do see one thing about the status quo that does look reasonably
annoying: the code expects that tranche IDs are going to stay
relatively small.  For example, consider a module foobar that uses DSM
+ LWLocks.  It won't do at all for each backend, on first use of the
foobar module, to do LWLockNewTrancheId() and then reuse that
tranche_id repeatedly for each new DSM - because over a system
lifetime of months, tranche IDs could grow into the millions, causing
LWLockTrancheArray to get really big (and eventually repalloc will
fail).  Rather, the programmer needs to ensure that
LWLockNewTrancheId() gets called *once per postmaster lifetime*,
perhaps by allocating a chunk of permanent shared memory and using
that to store the tranche_id that should be used each time an
individual backend fires up a DSM.  Considering that one of the goals
of dynamic shared memory is to allow modules to be loaded after
postmaster startup and still be able to do useful stuff, that's kind
of obnoxious.  I don't have a good idea what to do about it, though;
making LWLockTrancheArray anything other than a flat array looks
likely to slow down --enable-dtrace builds unacceptably.

Bottom line, I guess, is that I don't currently have any real idea how
to make this any better than it already is.  Maybe that will become
more clear as this facility (hopefully) acquires some users.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



pgsql-hackers by date:

Previous
From: Andres Freund
Date:
Subject: Re: Changeset Extraction v7.5
Next
From: Robert Haas
Date:
Subject: Re: GiST support for inet datatypes