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: Michael Paquier <michael@paquier.xyz>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, Laurenz Albe <laurenz.albe@cybertec.at>,
rootcause000@gmail.com, pgsql-bugs@lists.postgresql.org
Date: 2023-10-06T04:46:23Z
Lists: pgsql-bugs
Attachments
- hack.diff (text/x-patch) patch
On Fri, Oct 6, 2023 at 9:18 AM Thomas Munro <thomas.munro@gmail.com> wrote:
> On Fri, Oct 6, 2023 at 8:55 AM Thomas Munro <thomas.munro@gmail.com> wrote:
> > ... DELAY_CHKPT_COMPLETE ...
>
> About that... If the lights go out after the truncation and the
> delayed logging of the checkpoint, how do we know the truncation has
> actually reached the disk? mdtruncate() enqueues fsync() calls, but
> if we were already in phase 2 (see proc.h) of a checkpoint at that
> moment, they might be processed by the *next* checkpoint, not the one
> whose phase 3 we've carefully delayed there, no?
I didn't look into this for very long so I might be missing something
here, but I think there could be at least one bad sequence. If you
insert a couple of sleeps to jinx the scheduling, and hack
RelationTruncate() to request a checkpoint at a carefully chosen wrong
moment (see attached), then:
postgres=# create table t (i int);
CREATE TABLE
postgres=# insert into t select 1 from generate_series(1, 100);
INSERT 0 100
postgres=# checkpoint; -- checkpoint #1 just puts some data on disk
CHECKPOINT
postgres=# delete from t;
DELETE 100
postgres=# vacuum freeze t; -- truncates, starts unlucky checkpoint #2
VACUUM
If you trace the checkpointer's system calls you will see that
base/5/16384 (or whatever t's relfilenode is for you) is *not* fsync'd
by checkpoint #2. The following checkpoint #3 might eventually do it,
but if the kernel loses power after checkpoint #2 completes and there
is no checkpoint #3, the kernel might forget the truncation, and yet
replay starts too late to redo it. I think that bad sequence looks
like this:
P1: log truncate
P2: choose redo LSN
P1: DropRelationBuffers()
P2: CheckPointBuffers()
P2: ProcessSyncRequests()
P1: ftruncate()
P1: RegisterSyncRequest()
P2: log checkpoint
*** system loses power ***
I realise it is a different problem than the one reported, but it's
close. My initial thought is that perhaps we shouldn't allow a redo
LSN to be chosen until the sync request is registered, which is also
fairly close to the critical section boundaries being discussed for
ftruncate() error case. But that's not a phase the checkpoint delay
machinery currently knows how to delay. And there may well be better
ways...
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