Re: logical replication: restart_lsn can go backwards (and more), seems broken since 9.4
Tomas Vondra <tomas@vondra.me>
From: Tomas Vondra <tomas@vondra.me>
To: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Cc: PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Date: 2024-11-09T11:35:32Z
Lists: pgsql-hackers
Attachments
- 0001-restart_lsn-backwards-move-fix-and-asserts.patch (text/x-patch) patch 0001
- 0002-asserts-for-candidate-lsn-fields.patch (text/x-patch) patch 0002
On 11/8/24 15:57, Ashutosh Bapat wrote: > ... > > After examining the code before reading [2], I came to the same > conclusion as Masahiko-san in [2]. We install candidate_restart_lsn > based on the running transaction record whose LSN is between > restart_lsn and confirmed_flush_lsn. Since candidate_restart_valid of > such candidates would be lesser than any confirmed_flush_lsn received > from downstream. I am surprised that the fix suggested by Masahiko-san > didn't work though. The fix also fix the asymmetry, between > LogicalIncreaseXminForSlot and LogicalIncreaseRestartDecodingForSlot, > that you have pointed out in your next email. What behaviour do you > see with that fix applied? > > > [1] https://www.postgresql.org/message-id/Yz2hivgyjS1RfMKs%40depesz.com > [2] https://www.postgresql.org/message-id/CAD21AoBVhYnGBuW_o%3DwEGgTp01qiHNAx1a14b1X9kFXmuBe%3Dsg%40mail.gmail.com > > I read that message (and the earlier discussion multiple times) while investigating the issue, and TBH it's not very clear to me what the conclusion is :-( There's some discussion about whether the candidate fields should be reset on release or not. There are even claims that it might be legitimate to not reset the fields and update the restart_lsn. Using such "stale" LSN values seems rather suspicious to me, but I don't have a proof that it's incorrect. FWIW this unclarity is what I mentioned the policy/contract for candidate fields is not explained anywhere. That being said, I gave that fix a try - see the attached 0001 patch. It tweaks LogicalIncreaseRestartDecodingForSlot (it needs a bit more care because of the spinlock), and it adds a couple asserts to make sure the data.restart_lsn never moves back. And indeed, with this my stress test script does not crash anymore. But is that really correct? The lack of failure in one specific test does not really prove that. And then again - why should it be OK for the other candidate fields to move backwards? Isn't that suspicious? It sure seems counter-intuitive to me, and I'm not sure the code expects that. So in 0002 I added a couple more asserts to make sure the LSN fields only move forward, and those *do* continue to fail, and in some cases the amount by which the fields move back are pretty significant (multiple megabytes). Maybe it's fine if this "backwards move" never propagates to e.g. "restart_lsn", not sure. And I'm not sure which other fields should not move backwards (what about data.confirm_flush for example?). regards -- Tomas Vondra
Commits
-
Fix a possibility of logical replication slot's restart_lsn going backwards.
- e5ed873b1b4a 18.0 landed
- 568e78a653ee 17.2 landed
- f353911337cf 16.6 landed
- 91771b3fbbc3 15.10 landed
- 26c4e8968690 14.15 landed
- 15dc1abb17dd 13.18 landed
-
Introduce logical decoding.
- b89e151054a0 9.4.0 cited