public inbox for [email protected]  
help / color / mirror / Atom feed
From: Alexander Pyhalov <[email protected]>
To: [email protected]
Subject: buffer refcount leak in  foreign batch insert code
Date: Fri, 21 Apr 2023 13:07:03 +0300
Message-ID: <[email protected]> (raw)

Hi.

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

The issue was introduced in the following commit

commit b676ac443b6a83558d4701b2dd9491c0b37e17c4
Author: Tomas Vondra <[email protected]>
Date:   Fri Jun 11 20:19:48 2021 +0200

     Optimize creation of slots for FDW bulk inserts

In this commit we avoid recreating slots for each batch. But it seems 
that created slots should still be cleared in the end of 
ExecBatchInsert().

At least the attached patch seems to fix the issue.
-- 
Best regards,
Alexander Pyhalov,
Postgres Professional
CREATE EXTENSION postgres_fdw;
DO $d$
    BEGIN
        EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
            OPTIONS (dbname '$$||current_database()||$$',
                     port '$$||current_setting('port')||$$'
            )$$;
    END
$d$;
CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;

CREATE TABLE local_data (id int, data text);
INSERT INTO local_data SELECT i, 'test'|| i FROM generate_series(1, 10000) i;

CREATE TABLE sharded_data (id int, data text) PARTITION BY HASH(id);
CREATE TABLE sharded_data_p0  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 0);
CREATE TABLE sharded_data_p1_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p1  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 1)
SERVER loopback OPTIONS (table_name 'sharded_data_p1_remote');
CREATE TABLE sharded_data_p2_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p2  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 2)
SERVER loopback OPTIONS (table_name 'sharded_data_p2_remote');
CREATE TABLE sharded_data_p3_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p3  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 3)
SERVER loopback OPTIONS (table_name 'sharded_data_p3_remote');

insert into sharded_data select * from local_data ;
delete from sharded_data;

alter server loopback options (add batch_size '100');
insert into sharded_data select * from local_data ;


Attachments:

  [text/plain] repro_small.sql (1.4K, ../[email protected]/2-repro_small.sql)
  download | inline:
CREATE EXTENSION postgres_fdw;
DO $d$
    BEGIN
        EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
            OPTIONS (dbname '$$||current_database()||$$',
                     port '$$||current_setting('port')||$$'
            )$$;
    END
$d$;
CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;

CREATE TABLE local_data (id int, data text);
INSERT INTO local_data SELECT i, 'test'|| i FROM generate_series(1, 10000) i;

CREATE TABLE sharded_data (id int, data text) PARTITION BY HASH(id);
CREATE TABLE sharded_data_p0  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 0);
CREATE TABLE sharded_data_p1_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p1  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 1)
SERVER loopback OPTIONS (table_name 'sharded_data_p1_remote');
CREATE TABLE sharded_data_p2_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p2  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 2)
SERVER loopback OPTIONS (table_name 'sharded_data_p2_remote');
CREATE TABLE sharded_data_p3_remote (id int, data text);
CREATE FOREIGN TABLE sharded_data_p3  PARTITION OF sharded_data FOR VALUES WITH (modulus 4, remainder 3)
SERVER loopback OPTIONS (table_name 'sharded_data_p3_remote');

insert into sharded_data select * from local_data ;
delete from sharded_data;

alter server loopback options (add batch_size '100');
insert into sharded_data select * from local_data ;

  [text/x-diff] 0001-Fix-buffer-refcount-leak.patch (867B, ../[email protected]/3-0001-Fix-buffer-refcount-leak.patch)
  download | inline diff:
From 12d1fbf56c1c82d4659da484c2207539f396aac9 Mon Sep 17 00:00:00 2001
From: Alexander Pyhalov <[email protected]>
Date: Fri, 21 Apr 2023 12:54:41 +0300
Subject: [PATCH] Fix buffer refcount leak

The buffer refcount leak was introduced
in b676ac443b6a83558d4701b2dd9491c0b37e17c4
---
 src/backend/executor/nodeModifyTable.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 6aa8c03defb..14ab8382183 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1261,6 +1261,12 @@ ExecBatchInsert(ModifyTableState *mtstate,
 
 	if (canSetTag && numInserted > 0)
 		estate->es_processed += numInserted;
+
+	for (i = 0; i < numSlots; i++)
+	{
+		ExecClearTuple(slots[i]);
+		ExecClearTuple(planSlots[i]);
+	}
 }
 
 /*
-- 
2.34.1



view thread (6+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected]
  Subject: Re: buffer refcount leak in  foreign batch insert code
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox