pgsql: Fix crash in brininsertcleanup during logical replication. - Mailing list pgsql-committers

From Tom Lane
Subject pgsql: Fix crash in brininsertcleanup during logical replication.
Date
Msg-id E1tkrsf-000CXd-0u@gemulon.postgresql.org
Whole thread Raw
List pgsql-committers
Fix crash in brininsertcleanup during logical replication.

Logical replication crashes if the subscriber's partitioned table
has a BRIN index.  There are two independently blamable causes,
and this patch fixes both:

1. brininsertcleanup fails if called twice for the same IndexInfo,
because it half-destroys its BrinInsertState but leaves it still
linked from ii_AmCache.  brininsert would also fail in that state,
so it's pretty hard to see any advantage to this coding.  Fully
remove the BrinInsertState, instead, so that a new brininsert
call would create a new cache.

2. A logical replication subscriber sometimes does ExecOpenIndices
twice on the same ResultRelInfo, followed by doing ExecCloseIndices
twice; the second call reaches the brininsertcleanup bug.  Quite
aside from tickling unexpected cases in aminsertcleanup methods,
this seems very wasteful, because the IndexInfos built in the
first ExecOpenIndices call are just lost during the second call,
and have to be rebuilt at possibly-nontrivial cost.  We should
establish a coding rule that you don't do that.

The problematic coding is that when the target table is partitioned,
apply_handle_tuple_routing calls ExecFindPartition which does
ExecOpenIndices (and expects that ExecCleanupTupleRouting will
close the indexes again).  Using the ResultRelInfo made by
ExecFindPartition, it calls apply_handle_delete_internal or
apply_handle_insert_internal, both of which think they need to do
ExecOpenIndices/ExecCloseIndices for themselves.  They do in the main
non-partitioned code paths, but not here.  The simplest fix is to pull
their ExecOpenIndices/ExecCloseIndices calls out and put them in the
call sites for the non-partitioned cases.  (We could have refactored
apply_handle_update_internal similarly, but I did not do so today
because there's no bug there: the partitioned code path doesn't
call it.)

Also, remove the always-duplicative open/close calls within
apply_handle_tuple_routing itself.

Since brininsertcleanup and indeed the whole aminsertcleanup mechanism
are new in v17, there's no observable bug in older branches.  A case
could be made for trying to avoid these duplicative open/close calls
in the older branches, but for now it seems not worth the trouble and
risk of new bugs.

Bug: #18815
Reported-by: Sergey Belyashov <sergey.belyashov@gmail.com>
Discussion: https://postgr.es/m/18815-2a0407cc7f40b327@postgresql.org
Backpatch-through: 17

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/9ff68679b50f291d1c38e09748721a9732439508

Modified Files
--------------
src/backend/access/brin/brin.c           |  8 ++++---
src/backend/replication/logical/worker.c | 40 +++++++++++++++++++++-----------
src/test/subscription/t/013_partition.pl |  4 ++++
3 files changed, 35 insertions(+), 17 deletions(-)


pgsql-committers by date:

Previous
From: Tomas Vondra
Date:
Subject: pgsql: Consider BufFiles when adjusting hashjoin parameters
Next
From: Tomas Vondra
Date:
Subject: pgsql: Correct relation size estimate with low fillfactor