Re: BUG #17731: Server doesn't start after abnormal shutdown while creating unlogged tables

From: Karina Litskevich <litskevichkarina(at)gmail(dot)com>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org, kyzevan23(at)mail(dot)ru
Subject: Re: BUG #17731: Server doesn't start after abnormal shutdown while creating unlogged tables
Date: 2023-04-24 12:59:38
Message-ID: CACiT8ibXxDpJHO0gFtCXxD5nShnByW5OS37H2hPgjsoxBKD_Xw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

For unlogged tables and indexes init forks are created to simulate truncate on
server startup. In StartupXLOG() every main fork, for which corresponding init
fork exists, is deleted before replaying WAL, and then new main fork is created
by copying init fork:

ResetUnloggedRelations(UNLOGGED_RELATION_CLEANUP);
...
PerformWalRecovery();
...
ResetUnloggedRelations(UNLOGGED_RELATION_INIT);

So in case before WAL recovery main fork exists and init fork isn't, and during
recovery init fork is created, we get this problem. The second
ResetUnloggedRelations() call sees just created init fork and tries to create a
main fork from it expecting that the old main fork was already deleted by the
first ResetUnloggedRelations() call, but it wasn't because the main fork hasn't
corresponding init fork at that moment yet.

If you try to start server again, it will start successfully, as this time both
init and main forks will present from the beginning.

The situation, when main fork of the unlogged table is present but init fork is
not, can happen because main fork file isn't actually being deleted when table
is dropped. It's deletion is being postponed until the next checkpoint. See
comment before mdunlink():

/* ...
* Leaving the empty file in place prevents that relfilenumber
* from being reused. The scenario this protects us from is:
* 1. We delete a relation (and commit, and actually remove its file).
* 2. We create a new relation, which by chance gets the same relfilenumber as
* the just-deleted one (OIDs must've wrapped around for that to happen).
* 3. We crash before another checkpoint occurs.
* ...
*/

Theoretically, this applies to all versions, but the script somehow doesn't lead
to an error on REL_11_STABLE. I haven't investigated it yet.

I see two solutions: 1) keep init fork files until the next checkpoint as well
as main fork files, 2) ignore (rewrite if exists) presence of an empty main
fork file when copying from init fork. I found the latter less elegant so I
implemented the first one. The patch is attached.

Best regards,
Karina Litskevich
Postgres Professional: http://postgrespro.com/

Attachment Content-Type Size
v1-0001-Don-t-unlink-init-fork-until-the-next-checkpoint.patch text/x-patch 2.5 KB

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2023-04-24 14:34:36 BUG #17907: PostgresSQL 15.x contains OpenSSL DLLs (vulnerable to CVE-2023-0464, CVE-2023-0465 & CVE-2023-0466)
Previous Message Alexander Korotkov 2023-04-23 11:32:35 Re: BUG #17847: Unaligned memory access in ltree_gist