Re: Concurrency bug in UPDATE of partition-key

Поиск
Список
Период
Сортировка
От Dilip Kumar
Тема Re: Concurrency bug in UPDATE of partition-key
Дата
Msg-id CAFiTN-uDziEJM1LggsCBLik+b-KnKWD4Cw88LBLpo3OF-f1eMA@mail.gmail.com
обсуждение исходный текст
Ответ на Re: Concurrency bug in UPDATE of partition-key  (Amit Khandekar <amitdkhan.pg@gmail.com>)
Ответы Re: Concurrency bug in UPDATE of partition-key  (Dilip Kumar <dilipbalaut@gmail.com>)
Список pgsql-hackers
On Tue, Jun 5, 2018 at 8:03 PM, Amit Khandekar <amitdkhan.pg@gmail.com> wrote:
Attached is a rebased patch version. Also included it in the upcoming
commitfest :
https://commitfest.postgresql.org/18/1660/

In the rebased version, the new test cases are added in the existing
isolation/specs/partition-key-update-1.spec test.

/*
+  * If this is part of an UPDATE of partition-key, the
+  * epq tuple will contain the changes from this
+  * transaction over and above the updates done by the
+  * other transaction. The caller should now use this
+  * tuple as its NEW tuple, rather than the earlier NEW
+  * tuple.
+  */
+ if (epqslot)
+ {
+ *epqslot = my_epqslot;
+ return NULL;
+ }

I think we need simmilar fix if there are BR Delete trigger and the ExecDelete is blocked on heap_lock_tuple because the concurrent transaction is updating the same row.  Because in such case it would have already got the final tuple so the hep_delete will return MayBeUpdated.

Below test can reproduce the issue.

CREATE TABLE pa_target (key integer, val text) PARTITION BY LIST (key);
CREATE TABLE part1 PARTITION OF pa_target FOR VALUES IN (1);
CREATE TABLE part2 PARTITION OF pa_target FOR VALUES IN (2);

CREATE TABLE deleted_row (count int);
CREATE OR REPLACE FUNCTION br_delete() RETURNS trigger AS
$$BEGIN
insert into deleted_row values(OLD.key);
    RETURN OLD;
END;$$ LANGUAGE plpgsql;

CREATE TRIGGER test_br_trig BEFORE DELETE ON part1 FOR EACH ROW EXECUTE PROCEDURE br_delete();

INSERT INTO pa_target VALUES (1, 'initial1');

session1:
postgres=# BEGIN;
BEGIN
postgres=# UPDATE pa_target SET val = val || ' updated by update1' WHERE key = 1;
UPDATE 1

session2:
postgres=# UPDATE pa_target SET val = val || ' updated by update2', key = key + 1 WHERE key =1;
<block>

session1:
postgres=# commit;
COMMIT

UPDATE 1
postgres=# select * from pa_target ;
 key |             val             
-----+-----------------------------
   2 | initial1 updated by update2   --> session1's update is overwritten.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Simon Riggs
Дата:
Сообщение: Re: hot_standby_feedback vs excludeVacuum and snapshots
Следующее
От: Amit Kapila
Дата:
Сообщение: Re: hot_standby_feedback vs excludeVacuum and snapshots