mirror of
https://github.com/postgres/postgres.git
synced 2025-06-18 00:02:37 -04:00
During logical decoding, we advance catalog_xmin of logical too early in fast_forward mode, resulting in required catalog data being removed by vacuum. This mode is normally used to advance the slot without processing the changes, but we still can't let the slot's xmin to advance to an incorrect value. Commit f49a80c481 fixed a similar issue where the logical slot's catalog_xmin was getting advanced prematurely during non-fast-forward mode. During xl_running_xacts processing, instead of directly advancing the slot's xmin to the oldest running xid in the record, it allowed the xmin to be held back for snapshots that can be used for not-yet-replayed transactions, as those might consider older txns as running too. However, it missed the fact that the same problem can happen during fast_forward mode decoding, as we won't build a base snapshot in that mode, and the future call to get_changes from the same slot can miss seeing the required catalog changes leading to incorrect reslts. This commit allows building the base snapshot even in fast_forward mode to prevent the early advancement of xmin. Reported-by: Amit Kapila <amit.kapila16@gmail.com> Author: Zhijie Hou <houzj.fnst@fujitsu.com> Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com> Reviewed-by: shveta malik <shveta.malik@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Backpatch-through: 13 Discussion: https://postgr.es/m/CAA4eK1LqWncUOqKijiafe+Ypt1gQAQRjctKLMY953J79xDBgAg@mail.gmail.com Discussion: https://postgr.es/m/OS0PR01MB57163087F86621D44D9A72BF94BB2@OS0PR01MB5716.jpnprd01.prod.outlook.com
48 lines
2.2 KiB
Ruby
48 lines
2.2 KiB
Ruby
# Test advancement of the slot's oldest xmin
|
|
|
|
setup
|
|
{
|
|
SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); -- must be first write in xact
|
|
DROP TYPE IF EXISTS basket;
|
|
CREATE TYPE basket AS (apples integer, pears integer, mangos integer);
|
|
DROP TABLE IF EXISTS harvest;
|
|
CREATE TABLE harvest(fruits basket);
|
|
}
|
|
|
|
teardown
|
|
{
|
|
DROP TABLE IF EXISTS harvest;
|
|
DROP TYPE IF EXISTS basket;
|
|
SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
|
|
}
|
|
|
|
session "s0"
|
|
setup { SET synchronous_commit=on; }
|
|
step "s0_begin" { BEGIN; }
|
|
step "s0_getxid" { SELECT pg_current_xact_id() IS NULL; }
|
|
step "s0_alter" { ALTER TYPE basket DROP ATTRIBUTE mangos; }
|
|
step "s0_commit" { COMMIT; }
|
|
step "s0_checkpoint" { CHECKPOINT; }
|
|
step "s0_vacuum" { VACUUM pg_attribute; }
|
|
step "s0_get_changes" { SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); }
|
|
step "s0_advance_slot" { SELECT slot_name FROM pg_replication_slot_advance('isolation_slot', pg_current_wal_lsn()); }
|
|
|
|
session "s1"
|
|
setup { SET synchronous_commit=on; }
|
|
step "s1_begin" { BEGIN; }
|
|
step "s1_insert" { INSERT INTO harvest VALUES ((1, 2, 3)); }
|
|
step "s1_commit" { COMMIT; }
|
|
|
|
# Checkpoint with following get_changes forces xmin advancement. We do
|
|
# get_changes twice because if one more xl_running_xacts record had slipped
|
|
# before our CHECKPOINT, xmin will be advanced only on this record, thus not
|
|
# reaching value needed for vacuuming corresponding pg_attribute entry. ALTER of
|
|
# composite type is a rare form of DDL which allows T1 to see the tuple which
|
|
# will be removed (xmax set) before T1 commits. That is, interlocking doesn't
|
|
# forbid modifying catalog after someone read it (and didn't commit yet).
|
|
permutation "s0_begin" "s0_getxid" "s1_begin" "s1_insert" "s0_alter" "s0_commit" "s0_checkpoint" "s0_get_changes" "s0_get_changes" "s1_commit" "s0_vacuum" "s0_get_changes"
|
|
|
|
# Perform the same testing process as described above, but use advance_slot to
|
|
# forces xmin advancement during fast forward decoding.
|
|
permutation "s0_begin" "s0_getxid" "s1_begin" "s1_insert" "s0_alter" "s0_commit" "s0_checkpoint" "s0_advance_slot" "s0_advance_slot" "s1_commit" "s0_vacuum" "s0_get_changes"
|