Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rhGgP-00AX0g-EF for pgsql-bugs@arkaria.postgresql.org; Mon, 04 Mar 2024 22:21:18 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1rhGgN-00BG4s-Qa for pgsql-bugs@arkaria.postgresql.org; Mon, 04 Mar 2024 22:21:16 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rhGgN-00BG4k-6k for pgsql-bugs@lists.postgresql.org; Mon, 04 Mar 2024 22:21:15 +0000 Received: from mail-lj1-x232.google.com ([2a00:1450:4864:20::232]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1rhGgJ-002rmk-B4 for pgsql-bugs@lists.postgresql.org; Mon, 04 Mar 2024 22:21:13 +0000 Received: by mail-lj1-x232.google.com with SMTP id 38308e7fff4ca-2d23114b19dso62538801fa.3 for ; Mon, 04 Mar 2024 14:21:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aiven.io; s=google; t=1709590871; x=1710195671; darn=lists.postgresql.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Mmb0rab7v6L/fjSG96Gy32o9aGaDcTI2zxbGcBxwZPs=; b=SNFISRcrX5CEUr5sTxljixcs3awy5Px7dC/IbJlC5IMycLFqqZzcZ68vWjW/ASdyCl W2+HI4srKMdRikHBHxkVkg8RAZylyCbARQ76zLq4BzPtOr6fLXQh+Z0IDEKT6xCmM5Ri 12V3MVmKWotFwWn07EI/Oa8N8tUTfDsjbE3Xs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709590871; x=1710195671; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Mmb0rab7v6L/fjSG96Gy32o9aGaDcTI2zxbGcBxwZPs=; b=Uz1zNG6wodxjZmzocvgKsZHNyPDMeCWmhUxoHQk7/1nCrrQoeqa+V71WlY0cwf6/+o ZgWntgBeOzywIQKrv3tMCHTVbc1VenkI8/ug1XR6zD71qgP378yN7Jv7Cph/86eOyHnK 1f8hk034DIo0ixi9zUSn8zn3pDq3X7KloxQB1w31gyi7ZYObQuYzXHXhNuDtyX6q/CWo nPlI7JGfxg93fTEM5vzqRMR2jFzvD3J9ICEXjgTRbueLSME0kJW0gUFO9HhSekpajJ9A PSiTnEQLjPfgMtld4ISRRas0s3yQlUL/q4FiakNgV6chCaMKm5y4+bcDLA3Ml99rp+Tx DOyA== X-Gm-Message-State: AOJu0Yy2nb1oJE/W6GT+2N3e1UYHZL0KRMrjh9Fv8DR8JG4VBP0kxLip qrvQtXPl84qa8D3GVJ+lbGvzx9rlQ5iD7Q6bvSkFmepbK4l3sOegFm4S91VLz4Uqsan66HLrVKP A X-Google-Smtp-Source: AGHT+IFDBFKEFB+8m3pe9M/981Yx746hS8J+rzGTvXrCMpFPVxYgOK9R3glDLgZWXhkXD3a/A7dRmg== X-Received: by 2002:a2e:b00d:0:b0:2d2:8ad9:a667 with SMTP id y13-20020a2eb00d000000b002d28ad9a667mr122352ljk.17.1709590870613; Mon, 04 Mar 2024 14:21:10 -0800 (PST) Received: from aivenlaptop.localnet ([45.13.105.93]) by smtp.gmail.com with ESMTPSA id j10-20020ae9c20a000000b007871bac855fsm4796577qkg.47.2024.03.04.14.21.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Mar 2024 14:21:10 -0800 (PST) From: Ronan Dunklau To: Noah Misch Cc: pgsql-bugs Subject: Re: FSM Corruption (was: Could not read block at end of the relation) Date: Mon, 04 Mar 2024 23:21:07 +0100 Message-ID: <3549385.iIbC2pHGDl@aivenlaptop> In-Reply-To: <20240304190312.b6.nmisch@google.com> References: <1925490.taCxCBeP46@aivenlaptop> <20240304190312.b6.nmisch@google.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Le lundi 4 mars 2024, 20:03:12 CET Noah Misch a =E9crit : > On Mon, Mar 04, 2024 at 02:10:39PM +0100, Ronan Dunklau wrote: > > Le lundi 4 mars 2024, 00:47:15 CET Noah Misch a =E9crit : > > > On Tue, Feb 27, 2024 at 11:34:14AM +0100, Ronan Dunklau wrote: > You're using data_checksums, right? Thanks for the wal dump excerpts; I > agree with this summary thereof. Yes, data checksums so wal_log_hints is implied.=20 >=20 > > There are no traces of relation truncation happening in the WAL. >=20 > That is notable. >=20 > > This case only shows a single invalid entry in the FSM, but I've noticed > > as > > much as 62 blocks present in the FSM while they do not exist on disk, a= ll > > tagged with MaxFSMRequestSize so I suppose something is wrong with the > > bulk > > extension mechanism. >=20 > Is this happening after an OS crash, a replica promote, or a PITR restore= ?=20 I need to double check all occurences, but I wouldn't be surprised if they = all=20 went trough a replica promotion. > If so, I think I see the problem. We have an undocumented rule that FSM > shall not contain references to pages past the end of the relation. To > facilitate that, relation truncation WAL-logs FSM truncate. However, > there's no similar protection for relation extension, which is not > WAL-logged. We break the rule whenever we write FSM for block X before > some WAL record initializes block X. data_checksums makes the trouble > easier to hit, since it creates FPI_FOR_HINT records for FSM changes. A > replica promote or PITR ending just after the FSM FPI_FOR_HINT would yield > this broken state. While v16 RelationAddBlocks() made this easier to hit, > I suspect it's reproducible in all supported branches. For example, > lazy_scan_new_or_empty() and multiple index AMs break the rule via > RecordPageWithFreeSpace() on a PageIsNew() page. Very interesting. I understand the reasoning, and am now able to craft a ve= ry=20 crude test case, which I will refine into something more actionable:=20 - start a session 1, which will just vacuum our table continuously - start a ession 2, which will issue checkpoints continuously - in a session 3, COPY enough data so that we prealllocate too many pages.= In=20 my example, I 'm copying 33150 single integer rows, which fit on a bit more= =20 than 162 pages. The idea behind that is to make sure we don't fall on a rou= nd=20 number of pages, and we leave several iterations of the extend mechanism=20 running to issue a full page write of the fsm.=20 So to trigger the bug, it seems to me one needs to run in parallel: - COPY - VACUUM - CHECKPOINT Which would explain why a surprisingly large number of occurences I've seen= =20 seemed to involve a pg_restore invocation. >=20 > I think the fix is one of: >=20 > - Revoke the undocumented rule. Make FSM consumers resilient to the FSM > returning a now-too-large block number. Performance wise, that seems to be the better answer but won't this kind of= =20 built-in resilience encourage subtle bugs creeping in ? >=20 > - Enforce a new "main-fork WAL before FSM" rule for logged rels. For > example, in each PageIsNew() case, either don't update FSM or WAL-log an > init (like lazy_scan_new_or_empty() does when PageIsEmpty()). The FSM is not updated by the caller: in the bulk insert case, we=20 intentionally don't add them to the FSM. So having VACUUM WAL-log the page = in=20 lazy_scan_new_or_empty in the New case as you propose seems a very good ide= a. Performance wise that would keep the WAL logging outside of the backend=20 performing the preventive work for itself or others, and it should not be t= hat=20 many pages that it gives VACUUM too much work.=20 I can try my hand at such a patch it if looks like a good idea.=20 Thank you very much for your insights. Best regards, =2D- Ronan Dunklau