pg_ivm/expected/refresh_insert3.out

212 lines
4.3 KiB
Text
Raw Normal View History

Fix potential view inconsistency issues (#121) Previously, the view contents could become inconsistent with the base tables in the following scenarios: 1) A concurrent transaction modifies a base table and commits before the incremental view maintenance starts in the current transaction. 2) A concurrent transaction modifies a base table and commits before the create_immv or refresh_immv command generates data. 3) Concurrent transactions incrementally update a view with a self-join or modify multiple base tables simultaneously. Incremental updates of a view are generally performed sequentially using an exclusive lock. However, even if we are able to acquire the lock, a concurrent transaction may have already incrementally updated the view and been committed before we can acquire it. In REPEATABLE READ or SERIALIZABLE isolation levels, this could lead to an inconsistent view state, which is the cause of the first issue. To fix this, a new field, lastivmupdate, has been added to the pg_ivm_immv catalog to record the transaction ID of the most recent update to the view. Before performing view maintenance, the transaction ID is checked. If the transaction was still in progress at the start of the current transaction, an error is raised to prevent anomalies. To fix the second issue, the timing of CreateTrigger() has been moved to before data generation. This ensures that locks conflicting with table modifications have been acquired on all base tables. In addition, the latest snapshot is used in READ COMMITTED level during the data generation to reflect committed changes from concurrent transactions. Additionally, inconsistencies that cannot be avoided through locking are prevented by checking the transaction ID of the last view update, as done for the first issue. However, concurrent table modifications and create_immv execution still cannot be detected at the time of view creation. Therefore, create_immv raises a warning in REPEATABLE READ or SERIALIZABLE isolation levels, suggesting that the command be used in READ COMMITTED mode or that refresh_immv be executed afterward to ensure the view remains consistent. The third issue was caused by the snapshot used for checking tuple visibility in the table's pre-update state not being the latest one. To fix this, the latest snapshot is now used in READ COMMITTED mode. Isolation tests are also added. Issue #104
2025-03-10 09:26:54 +00:00
Parsed test spec with 2 sessions
starting permutation: s1 refresh s2 insert c1 check2 c2 mv
step s1: SELECT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
refresh_immv
------------
1
(1 row)
step s2: SELECT;
step insert: INSERT INTO a VALUES (2);
ERROR: could not obtain lock on materialized view "mv" during incremental maintenance
step c1: COMMIT;
step check2: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c2: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
(1 row)
check_mv
--------
ok
(1 row)
starting permutation: s1 refresh s2 c1 insert check2 c2 mv
step s1: SELECT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
refresh_immv
------------
1
(1 row)
step s2: SELECT;
step c1: COMMIT;
step insert: INSERT INTO a VALUES (2);
step check2: SELECT check_mv();
check_mv
--------
ok
(1 row)
step c2: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)
starting permutation: s1 s2 refresh insert c1 check2 c2 mv
step s1: SELECT;
step s2: SELECT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
refresh_immv
------------
1
(1 row)
step insert: INSERT INTO a VALUES (2);
ERROR: could not obtain lock on materialized view "mv" during incremental maintenance
step c1: COMMIT;
step check2: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c2: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
(1 row)
check_mv
--------
ok
(1 row)
starting permutation: s1 s2 insert refresh c2 check1 c1 mv
step s1: SELECT;
step s2: SELECT;
step insert: INSERT INTO a VALUES (2);
step refresh: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
step c2: COMMIT;
step refresh: <... completed>
ERROR: the materialized view is incrementally updated in concurrent transaction
step check1: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c1: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)
starting permutation: s1 s2 refresh c1 insert check2 c2 mv
step s1: SELECT;
step s2: SELECT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
refresh_immv
------------
1
(1 row)
step c1: COMMIT;
step insert: INSERT INTO a VALUES (2);
step check2: SELECT check_mv();
check_mv
--------
ok
(1 row)
step c2: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)
starting permutation: s2 insert s1 refresh c2 check1 c1 mv
step s2: SELECT;
step insert: INSERT INTO a VALUES (2);
step s1: SELECT;
step refresh: SELECT pgivm.refresh_immv('mv', true); <waiting ...>
step c2: COMMIT;
step refresh: <... completed>
ERROR: the materialized view is incrementally updated in concurrent transaction
step check1: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c1: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)
starting permutation: s2 insert s1 c2 refresh check1 c1 mv
step s2: SELECT;
step insert: INSERT INTO a VALUES (2);
step s1: SELECT;
step c2: COMMIT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
ERROR: the materialized view is incrementally updated in concurrent transaction
step check1: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c1: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)
starting permutation: s2 s1 insert c2 refresh check1 c1 mv
step s2: SELECT;
step s1: SELECT;
step insert: INSERT INTO a VALUES (2);
step c2: COMMIT;
step refresh: SELECT pgivm.refresh_immv('mv', true);
ERROR: the materialized view is incrementally updated in concurrent transaction
step check1: SELECT check_mv();
ERROR: current transaction is aborted, commands ignored until end of transaction block
step c1: COMMIT;
step mv: SELECT * FROM mv ORDER BY 1,2; SELECT check_mv();
x|y
-+-
1|1
2|2
(2 rows)
check_mv
--------
ok
(1 row)