Re: IPC/MultixactCreation on the Standby server
Ivan Bykov <i.bykov@modernsys.ru>
From: Ivan Bykov <i.bykov@modernsys.ru>
To: pgsql-hackers@lists.postgresql.org
Cc: Andrey Borodin <x4mmm@yandex-team.ru>
Date: 2025-11-24T14:32:26Z
Lists: pgsql-hackers
Hi, Andrey!
> Thanks for your review!
Review still in progress, sorry for the delay. I didn't have enough time to fully understand the changes you suggest, but it seems there is
only a small gap in my understanding of what the patch does. Here is my explanation of the problem.
The main problem
=============
The main problem is that we may lose session context before writing the offset to SLRU (but we may write
a WAL record). It seems that the writer process got stuck in the XLogInsert procedure or even failed between GetNewMultiXactId
and RecordNewMultiXact call. In this case, readers will wait to receive a conditional variable signal (from new multixacts)
but could not find a valid offset for the "failed" (it may be in WAL) multixid.
I illustrate this using the next diagram.
Writer Reader
--------------------------------------------------------------------------------
MultiXactIdCreateFromMembers
-> GetNewMultiXactId (101)
GetMultiXactIdMembers(100)
-> LWLockAcquire(MultiXactOffset)
-> read offset 100
-> read offset 101
-> LWLockRelease(MultiXactOffset)
offset 101 == 0
-> ConditionVariableSleep()
+--------------------------------------------------------------------------------------+
|-> XLogInsert |
+--------------------------------------------------------------------------------------+
-> RecordNewMultiXact
-> LWLockAcquire(MultiXactOffset)
-> write offset 101
-> LWLockRelease(MultiXactOffset)
-> ConditionVariableBroadcast(nextoff_cv);
-> retry:
-> LWLockAcquire(MultiXactOffset)
-> read offset 100
-> read offset 101
-> LWLockRelease(MultiXactOffset)
offset 101 != 0
-> length = offset 101 - read offset 100
-> LWLockAcquire(MultiXactMember)
-> write members 101
-> LWLockRelease(MultiXactOffset)
--------------------------------------------------------------------------------------
As far as I can see, your proposal seems to address exactly that problem.
The main difference from the former solution is writing to MultiXactOffset SLRU all required
information for the reader atomically on multiact insertion.
Before this change, we actually extended the multixact insertion time window to the next multixact
insertion time, and it seems a risky design.
I illustrate the new solution using the next diagram.
Writer Reader
--------------------------------------------------------------------------------
MultiXactIdCreateFromMembers
-> GetNewMultiXactId (100)
-> XLogInsert
-> RecordNewMultiXact
-> LWLockAcquire(MultiXactOffset)
-> write offset 100
-> write offset 101 *****************************************************************
-> LWLockRelease(MultiXactOffset)
GetMultiXactIdMembers(100)
-> LWLockAcquire(MultiXactOffset)
-> read offset 100
-> read offset 101
-> LWLockRelease(MultiXactOffset)
Assert(offset 101 == 0)
-> ConditionVariableSleep()
-> length = offset 101 - read offset 100
--------------------------------------------------------------------------------------
So if I understand the core idea of your solution right, I think that the code in the last patch
(v10-0001-Avoid-multixact-edge-case-2-by-writing-the-next-.patch) is correct and does what it should.
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Fix test to work with non-8kB block sizes
- 7c2061bdfba7 19 (unreleased) landed
-
Fix setting next multixid's offset at offset wraparound
- 48969555447f 14.21 landed
- b9a02b9780bc 15.16 landed
- 4d689a17693e 16.12 landed
- cad40cec24f3 17.8 landed
- 02ba5e3be4f3 18.2 landed
- 4d936c3fff1a 19 (unreleased) landed
-
Add test for multixid wraparound
- 7b81be9b4267 19 (unreleased) landed
-
Set next multixid's offset when creating a new multixid
- 81416e1016dd 14.21 landed
- 8cfb174a61eb 15.16 landed
- 635166913078 16.12 landed
- 8ba61bc06386 17.8 landed
- e46041fd973c 18.2 landed
- 789d65364cde 19 (unreleased) landed
-
psql: Improve tab completion for large objects.
- 14ee8e640300 19 (unreleased) cited
-
Refactor some repetitive SLRU code
- c61678551699 19 (unreleased) cited
-
Transaction IDs wrap around, per my proposal of 13-Aug-01. More
- bc7d37a525c0 7.2.1 cited