Re: BUG #18146: Rows reappearing in Tables after Auto-Vacuum Failure in PostgreSQL on Windows
Thomas Munro <thomas.munro@gmail.com>
From: Thomas Munro <thomas.munro@gmail.com>
To: Robert Haas <robertmhaas@gmail.com>
Cc: Michael Paquier <michael@paquier.xyz>,
Heikki Linnakangas <hlinnaka@iki.fi>, Alexander Lakhin <exclusion@gmail.com>, Tom Lane <tgl@sss.pgh.pa.us>, Laurenz Albe <laurenz.albe@cybertec.at>, rootcause000@gmail.com, pgsql-bugs@lists.postgresql.org
Date: 2024-12-11T13:32:41Z
Lists: pgsql-bugs
Attachments
- v5-0001-Fix-corruption-on-failed-interrupted-truncation.patch (application/x-patch) patch v5-0001
- v5-0002-Fix-pg_truncate_visibility_map-protocol.patch (application/x-patch) patch v5-0002
(Replies to separate messages from Michael and Robert below.) On Tue, Oct 29, 2024 at 8:49 PM Michael Paquier <michael@paquier.xyz> wrote: > I was looking at what you have here, and the split with > smgrtruncatefrom() to do the allocations in _mdfd_openseg() for > _mdfd_segpath() and _fdvec_resize() before entering in the critical > section for the physical truncation is elegant. Thanks for the sanity check. It took a few goes around to land there. > Perhaps this should have an assert based on CritSectionCount==0 to > force the rule. Added. > Don't you think that we'd better have a regression test on HEAD at > least? It should not be complicated. I can create one if you want, > perhaps for later if we want to catch the next minor release train. I'm probably lacking imagination here; I can see that it's useful to use the injection tooling for repros without the fix, but the fix is mostly a critical section. We know what critical sections do, they hold off interrupts and explode quite reliably on error, so there is not much left to test once it's fixed, no? > Making folks aware of the problem sounds kind of sensible seen from > here. In short, changing the signature of smgr_truncate() in a minor > release to fix what's a severe data corruption issue takes priority > IMO. Yeah. I'd avoid it if we had another way, but in the absence of epiphanies... On Fri, Nov 15, 2024 at 4:51 AM Robert Haas <robertmhaas@gmail.com> wrote: > I took a look at v4-0001 today and I think it looks fine. While I'm > not opposed to adding a test case, I think it's more important to fix > the bug at this point than to wait longer for a test case to show up. Thanks for taking a look! I started out to re-test and hopefully commit this today (having already committed 75818b3a from upthread last week), but while reviewing the reviews, this turned out to be a thing: > I do wonder whether the new smgrtruncatefrom() should be used > everywhere instead of just from one of the call sites, but even if > that's desirable long-term, doing this much is still a lot better than > doing nothing. This data corrupting bug has been known and understood > for more than 4 years at this point. There are only three callers of smgrtruncate() in our tree: 1. This one. 2. Its redo-time counterpart. 3. pg_truncate_visibility_map(), in contrib/pg_visibility. The recovery environment promotes errors of both types to FATAL (the "we have no handler" case in errstart()), and the postmaster handles startup failure a bit like a PANIC. Or do you think PANIC and more similar code would be better? As for pg_truncate_visibility_map(), it is a "a cut-down version of RelationTruncate". It logs in a different order (which probably doesn't really matter as it doesn't flush anyway) and it didn't get the memo about checkpoints. Maybe it's not such a big deal to be sloppy about whether or not the _vm file is truncated or not after crash recovery, given the semantics, I'm not sure. It surely has a version of the zombie tuples bug, though: If a _vm bit recently changed from "visible" to "not visible" and hasn't been written to disk yet, and it is booted out of the buffer pool by a call to pg_truncate_visibility_map() that is then cancelled in a call to WaitIO() for some other buffer so that ftruncate() is not reached, then an index-only scan might read in the old disk copy and show you a bunch of index tuples that are supposed to be invisible. I am curious about the non-flushing though. RelationTruncate() also doesn't flush if there is no fsm or vm. Perhaps it always flushes in practice since VACUUM itself creates those, I'm not entirely sure yet. If the log-first rule is abandoned and the flush is allowed to happen after the critical section, isn't there an opportunity for a primary to insert into but not flush the WAL, truncate the file, power-cycle, run recovery, and then carry on without ever telling a standby to truncate? Maybe that's OK for _vm (maybe the standby's untruncated copy of _vm would still be correct, and be maintained correctly by heap operations and everything would be fine, I'm not sure), by why would we want to allow this desynchronisation/confusion, just to make an infrequently used debugging tool go a bit faster? As for RelationTruncate(), if the non-flushing case is reachable, it would seem more obviously worse: it could leave the standby with a bunch of invisible tuples that the primary doesn't have, and eventually they'd either reference truncated CLOG or become visible again via wraparound rebirth, no? Am I missing something? Why wouldn't we just make both places flush unconditionally? PFA the first sketch of a patch to make pg_truncate_visibility_map() into... a cut-down version of RelationTruncate(). Still looking into the flushing, without which the comments in the patch are entirely bogus.
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Fix C error reported by Oracle compiler.
- 417d41c658b3 13.19 landed
- 049c8cb9a239 14.16 landed
- 190054e61f5d 15.11 landed
- 9defaaa1da60 16.7 landed
- 45aef9f6bb0f 17.3 landed
-
Restore smgrtruncate() prototype in back-branches.
- a1d17a894731 13.19 landed
- f154f028d856 14.16 landed
- 3181befdca71 15.11 landed
- c957d7444fcc 16.7 landed
- 66aaabe7a18f 17.3 landed
-
Fix corruption when relation truncation fails.
- 2280912165d6 13.19 landed
- 23c743b645a5 14.16 landed
- fb540b6aa5ab 15.11 landed
- ba02d24bacbb 16.7 landed
- 0350b876b074 17.3 landed
- 38c579b08988 18.0 landed
-
RelationTruncate() must set DELAY_CHKPT_START.
- a501fe5a971e 15.11 landed
- ad5aa7bfd042 16.7 landed
- d4ffbf47b2d4 17.3 landed
- 1168acbca475 13.19 landed
- 7d0b91a28421 14.16 landed
- 75818b3afbf8 18.0 landed
-
WAL-log inplace update before revealing it to other sessions.
- 8e7e672cdaa6 18.0 cited
-
Fix bugs in MultiXact truncation
- b1ffe3ff0b7e 17.0 cited
-
Fix possible recovery trouble if TRUNCATE overlaps a checkpoint.
- 412ad7a55639 15.0 cited