BUG #18241: PushTransaction may cause Standby to execute ItemIdMarkDead
PG Bug reporting form <noreply@postgresql.org>
From: PG Bug reporting form <noreply@postgresql.org>
To: pgsql-bugs@lists.postgresql.org
Cc: feichanghong@qq.com
Date: 2023-12-11T12:06:28Z
Lists: pgsql-bugs
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Prevent tuples to be marked as dead in subtransactions on standbys
- 4d45ecc9284a 12.18 landed
- d99294e77f1d 13.14 landed
- 0cfd3ddfe070 14.11 landed
- f5d8f59cae3e 15.6 landed
- 0e2c05af90ee 16.2 landed
- 8a7cbfce13d4 17.0 landed
-
Allow read only connections during recovery, known as Hot Standby.
- efc16ea52067 9.0.0 cited
The following bug has been logged on the website: Bug reference: 18241 Logged by: Fei Changhong Email address: feichanghong@qq.com PostgreSQL version: 16.1 Operating system: Operating system: centos 7,Kernel version: 5.10.13 Description: In scenarios involving subtransactions, we've discovered that Standby might mark index items as DEAD, which contravenes the design principle that "killed tuples" should not emerge during recovery, as stated in the comments of the RelationGetIndexScan function: /* * During recovery we ignore killed tuples and don't bother to kill them * either. We do this because the xmin on the primary node could easily be * later than the xmin on the standby node, so that what the primary * thinks is killed is supposed to be visible on standby. So for correct * MVCC for queries during recovery we must ignore these hints and check * all tuples. Do *not* set ignore_killed_tuples to true when running in a * transaction that was started during recovery. xactStartedInRecovery * should not be altered by index AMs. */ The issue can be reproduced through the following steps: (1) Initialize data on the Primary ``` create table t(a int, b int); alter table t alter column b type bigint; ``` (2)Standby gdb breakpoint at _bt_killitems ``` begin; savepoint savepoint_a; explain analyze select * from t; ``` We can observe that the query enters the _bt_killitems function, and an index item is marked as dead by the ItemIdMarkDead. We have analyzed the cause of the problem: The value of IndexScanDesc->xactStartedInRecovery is a key condition for determining whether an index item can be marked as DEAD. And it depends on CurrentTransactionState->startedInRecovery. However, PushTransaction does not assign a value to startedInRecovery when modifying CurrentTransactionState. Additionally, I have another question I'd like to ask: What specific problems might arise from a Standby marking index items as DEAD?