On Fri, Apr 21, 2023 at 07:16:03PM +0900, Michael Paquier wrote: > On Fri, Apr 21, 2023 at 01:07:03PM +0300, Alexander Pyhalov wrote: >> We've found that in cases like the one attached, when we insert into foreign >> partition with batch_size set, buffer refcount leak is detected. >> >> The above example we see a dozen of similar messages: >> >> repro_small.sql:31: WARNING: buffer refcount leak: [14621] >> (rel=base/16718/16732, blockNum=54, flags=0x93800000
This reminds me a lot of the recent multi-insert logic added to various DDL code paths for catalogs, bref.. The number of slots ready for a batch is tracked by ri_NumSlots, and it is reset to 0 each time a batch has been processed. How about resetting the counter at the same place as the slots are cleared, at the end of ExecBatchInsert() as the same time as when the slots are cleared? I was wondering as well about resetting the slot just before copying something into ri_Slots in ExecInsert() (actually close to the slot copy), which is something that would make the operation cheaper for large batches because the last batch could be cleaned up with ExecEndModifyTable(), but this makes the code much messier when a tuple is added into one of the slots as we would need to switch back-and-forth with es_query_cxt from what I can see, because th batches are inserted before any slot initialization is done. In short, I'm okay with what's proposed here and clean up things at the same time as ri_NumSlots. Another thing was the interaction of this change with triggers (delete, insert with returning and batches to flush pending inserts, etc.), and that looked correct to me (I have plugged in some of these triggers noisy on notices on the relations of the partitions tree). Self-reminder: the tests of postgres_fdw are rather long now, perhaps these should be split into more files in the future.. The attached is what I am finishing with, with a minimal regression test added to postgres_fdw. Two partitions are enough. Alexander, what do you think? -- Michael
From 6d9da4ecfbca7addd0450c2f5bb359a47a0f4e98 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Mon, 24 Apr 2023 09:51:48 +0900 Subject: [PATCH v2] Fix buffer refcount leak The buffer refcount leak was introduced in b676ac443b6a83558d4701b2dd9491c0b37e17c4. --- src/backend/executor/nodeModifyTable.c | 10 +++++++-- .../postgres_fdw/expected/postgres_fdw.out | 22 +++++++++++++++++++ contrib/postgres_fdw/sql/postgres_fdw.sql | 18 +++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 6aa8c03def..dc1a2ec551 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -856,7 +856,6 @@ ExecInsert(ModifyTableContext *context, resultRelInfo->ri_PlanSlots, resultRelInfo->ri_NumSlots, estate, canSetTag); - resultRelInfo->ri_NumSlots = 0; flushed = true; } @@ -1261,6 +1260,14 @@ ExecBatchInsert(ModifyTableState *mtstate, if (canSetTag && numInserted > 0) estate->es_processed += numInserted; + + /* Clean up all the slots, ready for the next batch */ + for (i = 0; i < numSlots; i++) + { + ExecClearTuple(slots[i]); + ExecClearTuple(planSlots[i]); + } + resultRelInfo->ri_NumSlots = 0; } /* @@ -1284,7 +1291,6 @@ ExecPendingInserts(EState *estate) resultRelInfo->ri_PlanSlots, resultRelInfo->ri_NumSlots, estate, mtstate->canSetTag); - resultRelInfo->ri_NumSlots = 0; } list_free(estate->es_insert_pending_result_relations); diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index fd5752bd5b..826baac9f1 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -6930,6 +6930,28 @@ select * from grem1; (2 rows) delete from grem1; +-- batch insert with foreign partitions. +-- This schema uses two partitions, one local and one remote with a modulo +-- to loop across all of them in batches. +create table tab_batch_local (id int, data text); +insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i; +create table tab_batch_sharded (id int, data text) partition by hash(id); +create table tab_batch_sharded_p0 partition of tab_batch_sharded + for values with (modulus 2, remainder 0); +create table tab_batch_sharded_p1_remote (id int, data text); +create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded + for values with (modulus 2, remainder 1) + server loopback options (table_name 'tab_batch_sharded_p1_remote'); +insert into tab_batch_sharded select * from tab_batch_local; +select count(*) from tab_batch_sharded; + count +------- + 45 +(1 row) + +drop table tab_batch_local; +drop table tab_batch_sharded; +drop table tab_batch_sharded_p1_remote; alter server loopback options (drop batch_size); -- =================================================================== -- test local triggers diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index c05046f867..15f3af6c29 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -1657,6 +1657,24 @@ insert into grem1 (a) values (1), (2); select * from gloc1; select * from grem1; delete from grem1; +-- batch insert with foreign partitions. +-- This schema uses two partitions, one local and one remote with a modulo +-- to loop across all of them in batches. +create table tab_batch_local (id int, data text); +insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i; +create table tab_batch_sharded (id int, data text) partition by hash(id); +create table tab_batch_sharded_p0 partition of tab_batch_sharded + for values with (modulus 2, remainder 0); +create table tab_batch_sharded_p1_remote (id int, data text); +create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded + for values with (modulus 2, remainder 1) + server loopback options (table_name 'tab_batch_sharded_p1_remote'); +insert into tab_batch_sharded select * from tab_batch_local; +select count(*) from tab_batch_sharded; +drop table tab_batch_local; +drop table tab_batch_sharded; +drop table tab_batch_sharded_p1_remote; + alter server loopback options (drop batch_size); -- =================================================================== -- 2.40.0
signature.asc
Description: PGP signature