Re: BUG #17821: Assertion failed in heap_update() due to heap pruning

Alexander Lakhin <exclusion@gmail.com>

From: Alexander Lakhin <exclusion@gmail.com>
To: pgsql-bugs@lists.postgresql.org
Date: 2023-03-04T06:00:00Z
Lists: pgsql-bugs

Attachments

02.03.2023 16:00, PG Bug reporting form wrote:
> #5  0x0000556725c44981 in ExceptionalCondition
> (conditionName=conditionName@entry=0x556725dc6b00 "ItemIdIsNormal(lp)",
> fileName=fileName@entry=0x556725dc48e0 "heapam.c",
> lineNumber=lineNumber@entry=3024) at assert.c:66
> ...
> 2023-03-02 15:22:13.031 MSK|law|test1|640094f5.1ba5ac|LOG:
> ExecuteGrantStmt(): before objectNamesToOids()
> 2023-03-02 15:22:13.031 MSK|law|test1|640094f5.1ba5ac|STATEMENT:  GRANT ALL
> ON pg_class TO public;
> 2023-03-02 15:22:13.031 MSK|law|test1|640094f5.1ba5ac|LOG:
> heap_page_prune_execute() before ItemIdSetUnused(); buffer: 2012, off: 24
> 2023-03-02 15:22:13.031 MSK|law|test1|640094f5.1ba5ac|STATEMENT:  GRANT ALL
> ON pg_class TO public;
> ...
>
> So it looks like the session 1ba5ac made linepointer 24 unused while
> pruning in the guts of objectNamesToOids(), then got the same
> offset (24) from the SearchSysCache1() and finally was surprised
> inside heap_update() to see an unused line pointer.
> This raises two questions for me.
> 1) Was it legal to prune that linepointer (what if ExecGrant do not
> perform
> heap_modify_tuple() in this case, will an unused line pointer be left
> behind?)?
> 2) Should page pruning be reflected in SysCache somehow?

Further investigation gave me a positive answer to the first question.
With more debug logging added I see that when that pruning executed
there was a redirection happened. There was dead items found in a tuple
chain starting from position 22, and redirection 22 -> 25 was performed,
so item 24 became unused.
The fragment of the detailed log is attached, and also you can look at
a dump of the modified page at the moment of the Assert.

SELECT * from heap_page_item_attrs(pg_read_binary_file('page.bin'), 
1259::oid, true);
shows:
...
  21 |   3600 |        1 |    225 |    680 |      0 |        0 | (10,21) 
|          33 |      11011 |     32 | 
1111111111111111111111111111111000000000 |       | ...
  22 |     25 |        2 |      0 |        |        | |         
|             |            | |                                          
|       |
  23 |      0 |        3 |      0 |        |        | |         
|             |            | |                                          
|       |
  24 |      0 |        0 |      0 |        |        | |         
|             |            | |                                          
|       |
  25 |   3368 |        1 |    225 | 222501 |      0 |        0 | (10,25) 
|       32801 |      10499 |     32 | 
1111111111111111111111111111111000000000 |       | ...
(25 rows)

So we have only the second question left.

Best regards,
Alexander

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Fix test races between syscache-update-pruned.spec and autovacuum.

  2. At update of non-LP_NORMAL TID, fail instead of corrupting page header.

  3. Disable runningcheck for src/test/modules/injection_points/specs.

  4. Merge copies of converting an XID to a FullTransactionId.

  5. Disable vacuum page skipping in selected test cases.