修复BRI触发器 + copy的内存持续增长问题

在原有的函数CopyFrom实现中,如果迭代中的元组无需插入(skip_tuple=true, BRI触发器会引起此情况),此种情况出现时
会导致per-tuple memory context不会reset,如果所有的元组均被触发器转移,会导致该内存上下文不断增长。
本次提交修复了此问题。
发生skip_tuple的情况,必然是BRI存在,可以在每次迭代都安全reset per-tuple memory context。
另:foreign table也需要每次reset(不会存在bulk insert的情况),本提交一并修复。
This commit is contained in:
cc_db_dev
2023-09-27 18:28:30 +08:00
parent c0aa776fee
commit ff5b4d66ee
3 changed files with 96 additions and 1 deletions

View File

@ -4282,7 +4282,7 @@ uint64 CopyFrom(CopyState cstate)
*/
if ((resultRelInfo->ri_TrigDesc != NULL &&
(resultRelInfo->ri_TrigDesc->trig_insert_before_row || resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) ||
cstate->volatile_defexprs) {
cstate->volatile_defexprs || isForeignTbl) {
useHeapMultiInsert = false;
} else {
useHeapMultiInsert = true;
@ -4819,6 +4819,8 @@ uint64 CopyFrom(CopyState cstate)
if (!skip_tuple && isForeignTbl) {
resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate, resultRelInfo, slot, NULL);
Assert(!useHeapMultiInsert);
resetPerTupCxt = true;
processed++;
} else if (!skip_tuple) {
/*
@ -5004,6 +5006,14 @@ uint64 CopyFrom(CopyState cstate)
* tuples inserted by an INSERT command.
*/
processed++;
} else {/*skip_tupe == true*/
/*
* only the before row insert trigget would make skip_tupe==true
* which useHeapMultiInsert must be false
* so we can safely reset the per-tuple memory context in next iteration
*/
Assert(useHeapMultiInsert == false);
resetPerTupCxt = true;
}
#ifdef PGXC
}

View File

@ -321,3 +321,45 @@ DROP TABLE x;
DROP TABLE y;
DROP FUNCTION fn_x_before();
DROP FUNCTION fn_x_after();
CREATE TABLE measurement (
city_id int not null,
logdate int not null,
peaktemp int,
unitsales int
);
CREATE TABLE measurement_movement (
city_id int not null,
logdate int not null,
peaktemp int,
unitsales int
);
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO measurement_movement VALUES (NEW.*);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_measurement_trigger
BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
COPY measurement from stdin;
select * from measurement_movement order by city_id;
city_id | logdate | peaktemp | unitsales
---------+---------+----------+-----------
10001 | 22 | 32 | 42
10002 | 23 | 33 | 43
10003 | 24 | 34 | 44
10004 | 25 | 35 | 45
10005 | 26 | 36 | 46
(5 rows)
select * from measurement order by city_id;
city_id | logdate | peaktemp | unitsales
---------+---------+----------+-----------
(0 rows)
drop trigger insert_measurement_trigger on measurement;
drop function measurement_insert_trigger;
drop table measurement;
drop table measurement_movement;

View File

@ -228,3 +228,46 @@ DROP TABLE x;
DROP TABLE y;
DROP FUNCTION fn_x_before();
DROP FUNCTION fn_x_after();
CREATE TABLE measurement (
city_id int not null,
logdate int not null,
peaktemp int,
unitsales int
);
CREATE TABLE measurement_movement (
city_id int not null,
logdate int not null,
peaktemp int,
unitsales int
);
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO measurement_movement VALUES (NEW.*);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_measurement_trigger
BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
COPY measurement from stdin;
10001 22 32 42
10002 23 33 43
10003 24 34 44
10004 25 35 45
10005 26 36 46
\.
select * from measurement_movement order by city_id;
select * from measurement order by city_id;
drop trigger insert_measurement_trigger on measurement;
drop function measurement_insert_trigger;
drop table measurement;
drop table measurement_movement;