Feature: POSIX Shared memory support

Started by Chris Marcellinoover 19 years ago26 messagespatches
Jump to latest
#1Chris Marcellino
maps@levelview.com

On Mac OS X and other BSD's, the default System V shared memory
limits are often very low and require adjustment for acceptable
performance. Particularly, when Postgres is included as part of
larger end-user friendly software products, these kernel settings are
often difficult to change for 2 reasons:

1. The (arbitrarily) limited resources must be shared by all programs
that use System V shared memory. For example on my Mac OS X computer,
I have Postgres running a standalone database, but also as part of
Apple Remote Desktop. Without manual adjustment, running both
simultaneously causes one of them to fail. Correcting this in any
robust way is challenging to automate for consumer-style (i.e. Mac)
installers.

2. On these BSD's, this System V shared memory is wired down and
cannot be swapped out for any reason. If Postgres is running as part
of another software program or is a lower priority, other programs
cannot use the potentially limited memory. This places the user or
developer in a tricky position of having to minimize overall system
impact, while permitting enough shared memory for Postgres to perform
well.

To this end, I have "ported" the svsv_shmem.c layer to use the POSIX
calls (which are some ways more robust w.r.t reducing collision by
using strings as shared memory id's, instead of ints).

In principle, this should not have any significant affect on
performance. Running PGBench on a few different load types gives very
similar results (-3%/+1%), that aren't very statistically
significant. Of course, on a un-tuned Mac OS X machine (where the
original SysV version is limited to the default 4MB) the POSIX
version outperforms significantly (+250%). Using the POSIX calls
helps minimize the kernel side of the tuning, which is a big plus for
integrated uses of Postgres, but also for other amateur installations
(i.e. Fink).

If this is appropriate for the distribution, it could become a
'contrib' add-on or it could be a autoconf custom build option until
it reached greater maturity.

Any thoughts? Suggestions? I would also appreciate any advice on more
sophisticate ways to measure the performance impacts of a change like
this.

Thanks,
Chris Marcellino
Apple Computer, Inc.

Attachments:

posix_shmem.capplication/octet-stream; name=posix_shmem.c; x-unix-mode=0644Download
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Chris Marcellino (#1)
Re: Feature: POSIX Shared memory support

Chris Marcellino <maps@levelview.com> writes:

To this end, I have "ported" the svsv_shmem.c layer to use the POSIX
calls (which are some ways more robust w.r.t reducing collision by
using strings as shared memory id's, instead of ints).

This has been suggested before, and rejected before, on the grounds that
the POSIX API provides no way to detect whether anyone else is attached
to the segment. Not being able to tell that is a tremendous robustness
hit for us. We are not going to risk destroying someone's database
(or in the alternative, failing to restart after most crashes, which
it looks like your patch would do) in order to make installation
fractionally easier.

I read through your patch in the hopes that you had a solution for this,
but all I find is a copied-and-pasted comment

/*
* We detect whether a shared memory segment is in use by seeing whether
* it (a) exists and (b) has any processes are attached to it.
*/

followed by code that does no such thing.

regards, tom lane

#3Michael Paesold
mpaesold@gmx.at
In reply to: Tom Lane (#2)
Re: Feature: POSIX Shared memory support

Tom Lane wrote:

Chris Marcellino <maps@levelview.com> writes:

To this end, I have "ported" the svsv_shmem.c layer to use the POSIX
calls (which are some ways more robust w.r.t reducing collision by
using strings as shared memory id's, instead of ints).

This has been suggested before, and rejected before, on the grounds that
the POSIX API provides no way to detect whether anyone else is attached
to the segment. Not being able to tell that is a tremendous robustness
hit for us. We are not going to risk destroying someone's database
(or in the alternative, failing to restart after most crashes, which
it looks like your patch would do) in order to make installation
fractionally easier.

I read through your patch in the hopes that you had a solution for this,
but all I find is a copied-and-pasted comment

/*
* We detect whether a shared memory segment is in use by seeing whether
* it (a) exists and (b) has any processes are attached to it.
*/

followed by code that does no such thing.

Just an idea, but would it be possible to have a small SysV area as an
"advisory lock" (using the existing semantics) to protect the POSIX segment.

Best Regards
Michael Paesold

#4Chris Marcellino
maps@levelview.com
In reply to: Michael Paesold (#3)
Re: Feature: POSIX Shared memory support

Tom, that is a definitely valid point and thanks for the feedback. I
assume that the 'more modern' string segment naming gave the POSIX
methods an edge in avoiding collision between other apps.
As far as detecting a) whether anyone else is currently attached to
that segment and b) whether an earlier existence of the current
backend was still attached to a segment, I presumed that checking the
pid's of the backend that owns the shared memory segment and checking
the data directory (both which the SysV code already does) would
suffice?
What am I forgetting?

Michael, that is an interesting idea. That might be an avenue to
explore if there isn't a simpler way.

Thanks,
Chris Marcellino

On Feb 6, 2007, at 7:51 AM, Michael Paesold wrote:

Show quoted text

Tom Lane wrote:

Chris Marcellino <maps@levelview.com> writes:

To this end, I have "ported" the svsv_shmem.c layer to use the
POSIX calls (which are some ways more robust w.r.t reducing
collision by using strings as shared memory id's, instead of ints).

This has been suggested before, and rejected before, on the
grounds that
the POSIX API provides no way to detect whether anyone else is
attached
to the segment. Not being able to tell that is a tremendous
robustness
hit for us. We are not going to risk destroying someone's database
(or in the alternative, failing to restart after most crashes, which
it looks like your patch would do) in order to make installation
fractionally easier.
I read through your patch in the hopes that you had a solution for
this,
but all I find is a copied-and-pasted comment

/*
* We detect whether a shared memory segment is in use by seeing
whether
* it (a) exists and (b) has any processes are attached to it.
*/

followed by code that does no such thing.

Just an idea, but would it be possible to have a small SysV area as
an "advisory lock" (using the existing semantics) to protect the
POSIX segment.

Best Regards
Michael Paesold

---------------------------(end of
broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org

#5Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Chris Marcellino (#4)
Re: Feature: POSIX Shared memory support

Chris Marcellino wrote:

Tom, that is a definitely valid point and thanks for the feedback. I
assume that the 'more modern' string segment naming gave the POSIX
methods an edge in avoiding collision between other apps.
As far as detecting a) whether anyone else is currently attached to
that segment and b) whether an earlier existence of the current
backend was still attached to a segment, I presumed that checking the
pid's of the backend that owns the shared memory segment and checking
the data directory (both which the SysV code already does) would
suffice?

Is there an API call to list all PIDs that are connected to a particular
segment?

--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#6Chris Marcellino
maps@levelview.com
In reply to: Alvaro Herrera (#5)
Re: Feature: POSIX Shared memory support

To my knowledge there is unfortunately not a portable call that does
that.
I was actually referring to the check that the current SysV code does
on the pid that is stored in the shmem header. I presume that if the
backend is dead, the kill(hdr->creatorPID, 0) returning zero would
suffice for confirming the existence of the other backend process.

Chris Marcellino

On Feb 6, 2007, at 10:32 AM, Alvaro Herrera wrote:

Show quoted text

Chris Marcellino wrote:

Tom, that is a definitely valid point and thanks for the feedback. I
assume that the 'more modern' string segment naming gave the POSIX
methods an edge in avoiding collision between other apps.
As far as detecting a) whether anyone else is currently attached to
that segment and b) whether an earlier existence of the current
backend was still attached to a segment, I presumed that checking the
pid's of the backend that owns the shared memory segment and checking
the data directory (both which the SysV code already does) would
suffice?

Is there an API call to list all PIDs that are connected to a
particular
segment?

--
Alvaro Herrera http://
www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Chris Marcellino (#6)
Re: Feature: POSIX Shared memory support

Chris Marcellino <maps@levelview.com> writes:

I was actually referring to the check that the current SysV code does
on the pid that is stored in the shmem header. I presume that if the
backend is dead, the kill(hdr->creatorPID, 0) returning zero would
suffice for confirming the existence of the other backend process.

No, that's not relevant, because only the postmaster's PID will be there
--- that test is actually more or less redundant with the existing
postmaster.pid lockfile checks.  The thing that the SysV attachment
count is useful for is detecting whether there are orphaned backends
still alive in the database (and potentially changing it, hence the
danger).

We've speculated on occasion about using file locking in some form as a
substitute mechanism for detecting this, but that seems to just bring
its own set of not-too-portable assumptions.

regards, tom lane

#8Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Chris Marcellino (#1)
Re: Feature: POSIX Shared memory support

From: "Chris Marcellino" <maps@levelview.com>

To this end, I have "ported" the svsv_shmem.c layer to use the POSIX
calls (which are some ways more robust w.r.t reducing collision by
using strings as shared memory id's, instead of ints).

I hope your work will be accepted. Setting IPC parameters is tedious
for normal users, and they sometimes miss the manual article and hit
the IPC resource shortage problem, particularly when the system
developers run multiple instances on a single machine at the same
time.
Then, how about semaphores? When I just do configure, PostgreSQL
seems to use SysV semaphores. But POSIX semaphore implementation is
prepared in src/backend/port/posix_sema.c. Why isn't it used by
default? Does it have any problem?
# Windows is good in this point, isn't it?

I'm sorry to ask you a question even though I've not read your patch
well. Does mmap(MAP_SHARED) need msync() to make the change by one
process visible to other processes? I found the following in the
manual page of mmap on Linux:

------------------------------------------------------------
MAP_SHARED Share this mapping with all other processes that
map this
object. Storing to the region is equivalent to writing to
the file. The file may not actually be updated until
msync(2) or munmap(2) are called.
------------------------------------------------------------

BTW, is the number of semaphores for dummy backends (eg bgwriter,
autovacuum) counted in PostgreSQL manual?

From: "Tom Lane" <tgl@sss.pgh.pa.us>

the POSIX API provides no way to detect whether anyone else is

attached

to the segment. Not being able to tell that is a tremendous

robustness

hit for us. We are not going to risk destroying someone's database
(or in the alternative, failing to restart after most crashes, which
it looks like your patch would do) in order to make installation
fractionally easier.

How is this done on Windows? Is it possible to count the number of
processes that attach a shared memory?

#9Chris Marcellino
maps@levelview.com
In reply to: Tsunakawa, Takayuki (#8)
Re: Feature: POSIX Shared memory support

Responses inline.

On Feb 6, 2007, at 7:05 PM, Takayuki Tsunakawa wrote:

From: "Chris Marcellino" <maps@levelview.com>

To this end, I have "ported" the svsv_shmem.c layer to use the POSIX
calls (which are some ways more robust w.r.t reducing collision by
using strings as shared memory id's, instead of ints).

I hope your work will be accepted. Setting IPC parameters is tedious
for normal users, and they sometimes miss the manual article and hit
the IPC resource shortage problem, particularly when the system
developers run multiple instances on a single machine at the same
time.

As Tom pointed out, the code I posted yesterday is not robust enough
for general consumption. I'm working on a better solution, which will
likely involve using a very small SysV shmem segment as a mutex of
sorts (as Michael Paesold suggested).

Then, how about semaphores? When I just do configure, PostgreSQL
seems to use SysV semaphores. But POSIX semaphore implementation is
prepared in src/backend/port/posix_sema.c. Why isn't it used by
default? Does it have any problem?

In this case, semaphore usage is unrelated to shared memory
shortages. Also, on many platforms the posix_sema's code is used.
Either way, Essentially, no one is running out of shared memory due
to semaphores.

# Windows is good in this point, isn't it?

From what I can tell, if you look at the Windows SysV shmem
emulation code in src/backend/port/win32/shmem.c, you will see in the
shmctl() function that the 'other process detection' code is not
implemented, since their is no corresponding Win32 API to implement
this. There is only so much you can do in that case.

As far as the other platforms go, any replacement for the SysV shmem
code should be as reliable as what preceded it.

Show quoted text

I'm sorry to ask you a question even though I've not read your patch
well. Does mmap(MAP_SHARED) need msync() to make the change by one
process visible to other processes? I found the following in the
manual page of mmap on Linux:

------------------------------------------------------------
MAP_SHARED Share this mapping with all other processes that
map this
object. Storing to the region is equivalent to writing to
the file. The file may not actually be updated until
msync(2) or munmap(2) are called.
------------------------------------------------------------

BTW, is the number of semaphores for dummy backends (eg bgwriter,
autovacuum) counted in PostgreSQL manual?

From: "Tom Lane" <tgl@sss.pgh.pa.us>

the POSIX API provides no way to detect whether anyone else is

attached

to the segment. Not being able to tell that is a tremendous

robustness

hit for us. We are not going to risk destroying someone's database
(or in the alternative, failing to restart after most crashes, which
it looks like your patch would do) in order to make installation
fractionally easier.

How is this done on Windows? Is it possible to count the number of
processes that attach a shared memory?

---------------------------(end of
broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tsunakawa, Takayuki (#8)
Re: Feature: POSIX Shared memory support

"Takayuki Tsunakawa" <tsunakawa.takay@jp.fujitsu.com> writes:

From: "Tom Lane" <tgl@sss.pgh.pa.us>

the POSIX API provides no way to detect whether anyone else is
attached to the segment. Not being able to tell that is a tremendous
robustness hit for us.

How is this done on Windows? Is it possible to count the number of
processes that attach a shared memory?

AFAIK the Windows port is simply wrong/insecure on this point --- it's
one of the reasons you'll never see me recommending Windows as the OS
for a production Postgres server.

regards, tom lane

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Chris Marcellino (#9)
Re: Feature: POSIX Shared memory support

Chris Marcellino <maps@levelview.com> writes:

As Tom pointed out, the code I posted yesterday is not robust enough
for general consumption. I'm working on a better solution, which will
likely involve using a very small SysV shmem segment as a mutex of
sorts (as Michael Paesold suggested).

One problem with Michael's idea is that it gives up one of the better
arguments for having a POSIX option, namely to allow us to run on
platforms where SysV shmem support is not there at all.

I'm not sure whether the idea can be implemented without creating new
failure modes; that will have to wait on seeing a patch. But the
strength of the coupling between the SysV and POSIX segments is
certainly going to be a red-flag item to look at.

Then, how about semaphores? When I just do configure, PostgreSQL
seems to use SysV semaphores. But POSIX semaphore implementation is
prepared in src/backend/port/posix_sema.c. Why isn't it used by
default? Does it have any problem?

In this case, semaphore usage is unrelated to shared memory
shortages. Also, on many platforms the posix_sema's code is used.
Either way, Essentially, no one is running out of shared memory due
to semaphores.

AFAIK the only platform where the POSIX sema code is really used is
Darwin (OS X), and it is not something I'd use there if I had a choice.
The problem with it is that *every* semaphore corresponds to an open
file handle in the postmaster that has to be inherited by *every* forked
child. So N backend slots cost you O(N^2) in kernel filehandles and
process fork overhead, plus if N is big you're taking a serious hit in
the number of disk files any one backend can have open. This problem
may be specific to Darwin's implementation of the POSIX spec, but it's
real enough there. If you trawl the archives you'll probably notice a
lack of people running big Postgres installations on Darwin, and this is
why.

regards, tom lane

#12Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Chris Marcellino (#1)
Re: Feature: POSIX Shared memory support

ep

#13Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Chris Marcellino (#1)
Re: Feature: POSIX Shared memory support

Then, how about semaphores? When I just do configure, PostgreSQL
seems to use SysV semaphores. But POSIX semaphore implementation

is

prepared in src/backend/port/posix_sema.c. Why isn't it used by
default? Does it have any problem?

Either way, Essentially, no one is running out of shared memory due
to semaphores.
In this case, semaphore usage is unrelated to shared memory
shortages.

Yes, of course, shared memory is not related to semaphores.

Also, on many platforms the posix_sema's code is used.

Really? When I run 'configure' without any parameter on Red Hat
Enterprise Linux 4.0 (kernel 2.6.x), PostgreSQL uses SysV semaphores.
I confirmed that by seeing the result of 'ipcs -u'. What platforms is
POSIX sema used by PostgreSQL by default?

#14Chris Marcellino
maps@levelview.com
In reply to: Tsunakawa, Takayuki (#13)
Re: Feature: POSIX Shared memory support

Yes, as Tom pointed out. Sorry, I misread the autoconf file. I've
gotten quite used to Darwin == BSD.
I've added a note to my todo list to look into the posix semaphore
performance on the Darwin side.

--Chris

On Feb 6, 2007, at 8:32 PM, Takayuki Tsunakawa wrote:

Show quoted text

Then, how about semaphores? When I just do configure, PostgreSQL
seems to use SysV semaphores. But POSIX semaphore implementation

is

prepared in src/backend/port/posix_sema.c. Why isn't it used by
default? Does it have any problem?

Either way, Essentially, no one is running out of shared memory due
to semaphores.
In this case, semaphore usage is unrelated to shared memory
shortages.

Yes, of course, shared memory is not related to semaphores.

Also, on many platforms the posix_sema's code is used.

Really? When I run 'configure' without any parameter on Red Hat
Enterprise Linux 4.0 (kernel 2.6.x), PostgreSQL uses SysV semaphores.
I confirmed that by seeing the result of 'ipcs -u'. What platforms is
POSIX sema used by PostgreSQL by default?

---------------------------(end of
broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

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

#15Chris Marcellino
maps@levelview.com
In reply to: Tom Lane (#11)
Re: Feature: POSIX Shared memory support

Attached is a beta of the POSIX shared memory layer. It is 75% the
original sysv_shmem.c code. I'm looking for ways to refactor it down
a bit, while changing as little of the tried-and-tested code as
possible. I though I'd put it out there for comments.

Of course, unfortunately it is more complicated than the original as
it uses both sets of API. Also, I haven't tested the crash recovery
thoroughly. The POSIX code could be used Windows-style (i.e. no
crash recovery) if one ifdef'd out the SysV calls properly, if they
had such a POSIX-only platform they needed to run Postgres on.

Using both API is certainly not ideal. You mentioned,

We've speculated on occasion about using file locking in some form
as a
substitute mechanism for detecting this, but that seems to just bring
its own set of not-too-portable assumptions

What sort of file locking did you have in mind? Do you think this
might be worth me trying?

Thanks for your help,
Chris Marcellino

Attachments:

posix_shmem.capplication/octet-stream; name=posix_shmem.c; x-unix-mode=0644Download
#16Andrew Dunstan
andrew@dunslane.net
In reply to: Tom Lane (#7)
Re: Feature: POSIX Shared memory support

Tom Lane wrote:

We've speculated on occasion about using file locking in some form as a
substitute mechanism for detecting this, but that seems to just bring
its own set of not-too-portable assumptions.

Maybe we should look some more at that. Use of file locking was one
thought I had today after I saw Tom's earlier comments.

Perl provides a moderately portable flock(), which we use in fact in
buildfarm to stop it from running more than one at a time on a given repo
copy.

The Perl description starts thus:

Calls flock(2), or an emulation of it, on FILEHANDLE. Returns
true for success, false on failure. Produces a fatal error if
used on a machine that doesn't implement flock(2), fcntl(2)
locking, or lockf(3). "flock" is Perl's portable file locking
interface, although it locks only entire files, not records.

Note that this means it works on every platform that has ever reported on
buildfarm.

Maybe we can borrow some code.

cheers

andrew

#17Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#10)
Re: Feature: POSIX Shared memory support

On Tue, Feb 06, 2007 at 11:08:51PM -0500, Tom Lane wrote:

"Takayuki Tsunakawa" <tsunakawa.takay@jp.fujitsu.com> writes:

From: "Tom Lane" <tgl@sss.pgh.pa.us>

the POSIX API provides no way to detect whether anyone else is
attached to the segment. Not being able to tell that is a tremendous
robustness hit for us.

How is this done on Windows? Is it possible to count the number of
processes that attach a shared memory?

AFAIK the Windows port is simply wrong/insecure on this point --- it's
one of the reasons you'll never see me recommending Windows as the OS
for a production Postgres server.

What exactly is the failure case? Might be able to figure out a way to
do what we want on win32 even if it's not possible to do it exactly with
the sysv semantics.

//Magnus

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#17)
Re: Feature: POSIX Shared memory support

Magnus Hagander <magnus@hagander.net> writes:

On Tue, Feb 06, 2007 at 11:08:51PM -0500, Tom Lane wrote:

AFAIK the Windows port is simply wrong/insecure on this point --- it's
one of the reasons you'll never see me recommending Windows as the OS
for a production Postgres server.

What exactly is the failure case? Might be able to figure out a way to
do what we want on win32 even if it's not possible to do it exactly with
the sysv semantics.

kill -9 postmaster (only), then try to start new postmaster. This
should succeed if and only if there are no live orphaned backends.
An implementation that hasn't got a direct test for the presence of
backends can only get one of the two cases correct.

On Windows (or really any EXEC_BACKEND platform) there's an additional
problem, which is that even with an attach count you have a race
condition: what if the postmaster launched a new backend just before
dying, and that process has not yet re-attached to shared memory?
I don't think this is a big problem in practice, because most people
don't feel a need for an automated postmaster-restarting monitor, and
so the time scale for human intervention is too long to hit the race
condition. But it's annoying from a theoretical perspective.

It's probably possible to replace the attach-count test with some sort
of file locking convention --- eg if all the backends hold some type of
shared lock on postmaster.pid. This seems unlikely to be much more
portable than the attach-count solution as far as Unixen go, but if
we're looking for a Windows-specific solution that's where I'd look.

regards, tom lane

#19Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Andrew Dunstan (#16)
Re: Feature: POSIX Shared memory support

Andrew Dunstan wrote:

Maybe we should look some more at that. Use of file locking was one
thought I had today after I saw Tom's earlier comments.

Perl provides a moderately portable flock(), which we use in fact in
buildfarm to stop it from running more than one at a time on a given repo
copy.

But does it work over NFS? On my system, the flock manpage claims it
doesn't, lockf doesn't say and fcntl also doesn't say, but the flock
manpage says fcntl does. A lot of people runs servers on NFS, even
though we recommend they don't. And there are those strange hybrids
like SANs, NASes or what have you.

One serious problem is that if the lock doesn't work for some reason
like NFSness, it will fail silently, which is not acceptable.

--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

#20Andrew Dunstan
andrew@dunslane.net
In reply to: Alvaro Herrera (#19)
Re: Feature: POSIX Shared memory support

Alvaro Herrera wrote:

Andrew Dunstan wrote:

Maybe we should look some more at that. Use of file locking was one
thought I had today after I saw Tom's earlier comments.

Perl provides a moderately portable flock(), which we use in fact in
buildfarm to stop it from running more than one at a time on a given repo
copy.

But does it work over NFS? On my system, the flock manpage claims it
doesn't, lockf doesn't say and fcntl also doesn't say, but the flock
manpage says fcntl does. A lot of people runs servers on NFS, even
though we recommend they don't. And there are those strange hybrids
like SANs, NASes or what have you.

One serious problem is that if the lock doesn't work for some reason
like NFSness, it will fail silently, which is not acceptable.

Fair point. Perl in fact uses whatever it can from the underlying
system, preferring (I think) flock, then fcntl, then lockf. So its
flock is quite possibly not NFS safe in many cases.

cheers

andrew

#21Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Andrew Dunstan (#16)
#22Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#18)
#23Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#22)
#24Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#23)
#25Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#24)
#26Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#25)