# v04-0008: an UPDATE that commits while REPACK (CONCURRENTLY) waits for # AccessExclusiveLock on the table is replayed after the lock is granted. # LockAcquireExtended() assigned REPACK an XID for the standby lock record # (wal_level >= replica), so the replayed heap_update() runs with a valid # top XID and add_to_xmax of the original transaction. setup { CREATE EXTENSION injection_points; CREATE TABLE t(i int PRIMARY KEY, j int); INSERT INTO t SELECT x, 0 FROM generate_series(1, 100) x; } teardown { DROP TABLE t; DROP EXTENSION injection_points; } session s1 setup { SELECT injection_points_set_local(); SELECT injection_points_attach('repack-concurrently-before-lock', 'wait'); } step repack { REPACK (CONCURRENTLY) t; } step check { SELECT count(*), sum(j) FROM t; } session s2 step begin { BEGIN; } step upd { UPDATE t SET j = j + 1 WHERE i = 10; } step del { DELETE FROM t WHERE i = 20; } step commit { COMMIT; } session s3 step wakeup { SELECT injection_points_detach('repack-concurrently-before-lock'); SELECT injection_points_wakeup('repack-concurrently-before-lock'); } # Make sure REPACK is queued for AccessExclusiveLock before s2 commits. step waitlock { DO $$ BEGIN WHILE NOT EXISTS (SELECT 1 FROM pg_locks WHERE relation = 't'::regclass AND NOT granted AND mode = 'AccessExclusiveLock') LOOP PERFORM pg_sleep(0.01); END LOOP; END $$; } permutation repack begin upd wakeup waitlock commit check permutation repack begin del wakeup waitlock commit check # Controls: the change commits before REPACK leaves the injection point, # so it is replayed before the lock is requested. permutation repack begin upd commit wakeup check permutation repack begin del commit wakeup check