I've been continuing work on modifying the system to let foreign keys
coexist concurrently with updates that do not touch the "key" columns.
I've made a lot of progress and things seem to be working rather well.
However, I just struck an obstacle that seemed problematic: handling the
truncation of the MultiXactId space when they are no longer needed.

I hadn't stopped to think much about this, regarding it as a trivial
problem to change multixact.c to be just like clog.c.  However, when it
came to actually doing it, I immediately realized that this cannot work,
because they don't share a common numeric space -- the mxact counter can
be anywhere, unrelated to the Xid counter.  There's no way to figure out
the mutixact truncation point from purely Xid data.

In search of solutions to this problem, two things came to mind:

1. Track MultiXact offset generation just as we track Xid generation.
This means that after vacuum we immediately know where to truncate.

2. Make them share a common numeric space.

Both those two solutions come at a very high cost.  #1 means that we
need some sort of "frozenmxact" column in pg_class and pg_database.  So
we'd know easily and precisely where to truncate mxact; but we would
bloat those catalogs for something that's not as important.  (We eat the
cost of maintaining relfrozenxid and datfrozenxid because it's necessary
for the system to work at all; but in the mxact case, we're talking
about something that's merely a concurrency optimization).

In the case of #2, we avoid having to add those columns, by having
multixact offsets be assigned by GetNewTransactionId; thus, we can
easily know where to truncate just by truncating at the same spot that
we truncate pg_clog.  The problem with this idea is that there would be
huge areas of pg_multixact/offset that are completely unused, because
they would correspond to the values assigned to Xids themselves.  This
would lead to bloat of multixact.  It would also lead to shortening the
useful Xid space, thus leading to shorter times to freeze vacuum.  This
is, of course, completely unacceptable.

So I had to look for something else -- and I think I have it: have
multixact itself track its truncation position relative to Xid.  Each
pg_multixact/offset segment would store ReadNewTransactionId at the time
it is created.  Whenever vacuum attempts to run pg_clog truncation, it
would also pass that Xid to multixact truncation; this would scan
existing segments and delete those that come before the one marked with
the maximum Xid previous to the pg_clog truncation point.

Doing this will require hacking the SLRU truncation logic a bit, so that
it's possible to have it scan segments with a callback in some fashion.


Álvaro Herrera <alvhe...@alvh.no-ip.org>

Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Reply via email to