mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-25 17:27:19 +02:00
According to buildfarm member sungazer, the behavior of VACUUM can be
unstable in these tests even if we prevent autovacuum from running on
the tables in question, apparently because even a manual vacuum can
behave differently depending on whether anything else is running that
holds back the global xmin. So use a temporary table instead, which
as of commit a7212be8b9
enables
vacuuming using a more aggressive cutoff.
This approach can't be used for the regression test that involves a
materialized view, but that test doesn't run vacuum, so it shouldn't
be prone to this particular failure mode.
Analysis by Tom Lane. Patch by Ashutosh Sharma and me.
Discussion: http://postgr.es/m/665524.1599948007@sss.pgh.pa.us
179 lines
4.4 KiB
Plaintext
179 lines
4.4 KiB
Plaintext
create extension pg_surgery;
|
|
-- create a normal heap table and insert some rows.
|
|
-- use a temp table so that vacuum behavior doesn't depend on global xmin
|
|
create temp table htab (a int);
|
|
insert into htab values (100), (200), (300), (400), (500);
|
|
-- test empty TID array
|
|
select heap_force_freeze('htab'::regclass, ARRAY[]::tid[]);
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
-- nothing should be frozen yet
|
|
select * from htab where xmin = 2;
|
|
a
|
|
---
|
|
(0 rows)
|
|
|
|
-- freeze forcibly
|
|
select heap_force_freeze('htab'::regclass, ARRAY['(0, 4)']::tid[]);
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
-- now we should have one frozen tuple
|
|
select ctid, xmax from htab where xmin = 2;
|
|
ctid | xmax
|
|
-------+------
|
|
(0,4) | 0
|
|
(1 row)
|
|
|
|
-- kill forcibly
|
|
select heap_force_kill('htab'::regclass, ARRAY['(0, 4)']::tid[]);
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
-- should be gone now
|
|
select * from htab where ctid = '(0, 4)';
|
|
a
|
|
---
|
|
(0 rows)
|
|
|
|
-- should now be skipped because it's already dead
|
|
select heap_force_kill('htab'::regclass, ARRAY['(0, 4)']::tid[]);
|
|
NOTICE: skipping tid (0, 4) for relation "htab" because it is marked dead
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
select heap_force_freeze('htab'::regclass, ARRAY['(0, 4)']::tid[]);
|
|
NOTICE: skipping tid (0, 4) for relation "htab" because it is marked dead
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
-- freeze two TIDs at once while skipping an out-of-range block number
|
|
select heap_force_freeze('htab'::regclass,
|
|
ARRAY['(0, 1)', '(0, 3)', '(1, 1)']::tid[]);
|
|
NOTICE: skipping block 1 for relation "htab" because the block number is out of range
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
-- we should now have two frozen tuples
|
|
select ctid, xmax from htab where xmin = 2;
|
|
ctid | xmax
|
|
-------+------
|
|
(0,1) | 0
|
|
(0,3) | 0
|
|
(2 rows)
|
|
|
|
-- out-of-range TIDs should be skipped
|
|
select heap_force_freeze('htab'::regclass, ARRAY['(0, 0)', '(0, 6)']::tid[]);
|
|
NOTICE: skipping tid (0, 0) for relation "htab" because the item number is out of range
|
|
NOTICE: skipping tid (0, 6) for relation "htab" because the item number is out of range
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
-- set up a new table with a redirected line pointer
|
|
-- use a temp table so that vacuum behavior doesn't depend on global xmin
|
|
create temp table htab2(a int);
|
|
insert into htab2 values (100);
|
|
update htab2 set a = 200;
|
|
vacuum htab2;
|
|
-- redirected TIDs should be skipped
|
|
select heap_force_kill('htab2'::regclass, ARRAY['(0, 1)']::tid[]);
|
|
NOTICE: skipping tid (0, 1) for relation "htab2" because it redirects to item 2
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
-- now create an unused line pointer
|
|
select ctid from htab2;
|
|
ctid
|
|
-------
|
|
(0,2)
|
|
(1 row)
|
|
|
|
update htab2 set a = 300;
|
|
select ctid from htab2;
|
|
ctid
|
|
-------
|
|
(0,3)
|
|
(1 row)
|
|
|
|
vacuum freeze htab2;
|
|
-- unused TIDs should be skipped
|
|
select heap_force_kill('htab2'::regclass, ARRAY['(0, 2)']::tid[]);
|
|
NOTICE: skipping tid (0, 2) for relation "htab2" because it is marked unused
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
-- multidimensional TID array should be rejected
|
|
select heap_force_kill('htab2'::regclass, ARRAY[['(0, 2)']]::tid[]);
|
|
ERROR: argument must be empty or one-dimensional array
|
|
-- TID array with nulls should be rejected
|
|
select heap_force_kill('htab2'::regclass, ARRAY[NULL]::tid[]);
|
|
ERROR: array must not contain nulls
|
|
-- but we should be able to kill the one tuple we have
|
|
select heap_force_kill('htab2'::regclass, ARRAY['(0, 3)']::tid[]);
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
-- materialized view.
|
|
-- note that we don't commit the transaction, so autovacuum can't interfere.
|
|
begin;
|
|
create materialized view mvw as select a from generate_series(1, 3) a;
|
|
select * from mvw where xmin = 2;
|
|
a
|
|
---
|
|
(0 rows)
|
|
|
|
select heap_force_freeze('mvw'::regclass, ARRAY['(0, 3)']::tid[]);
|
|
heap_force_freeze
|
|
-------------------
|
|
|
|
(1 row)
|
|
|
|
select * from mvw where xmin = 2;
|
|
a
|
|
---
|
|
3
|
|
(1 row)
|
|
|
|
select heap_force_kill('mvw'::regclass, ARRAY['(0, 3)']::tid[]);
|
|
heap_force_kill
|
|
-----------------
|
|
|
|
(1 row)
|
|
|
|
select * from mvw where ctid = '(0, 3)';
|
|
a
|
|
---
|
|
(0 rows)
|
|
|
|
rollback;
|
|
-- check that it fails on an unsupported relkind
|
|
create view vw as select 1;
|
|
select heap_force_kill('vw'::regclass, ARRAY['(0, 1)']::tid[]);
|
|
ERROR: "vw" is not a table, materialized view, or TOAST table
|
|
select heap_force_freeze('vw'::regclass, ARRAY['(0, 1)']::tid[]);
|
|
ERROR: "vw" is not a table, materialized view, or TOAST table
|
|
-- cleanup.
|
|
drop view vw;
|
|
drop extension pg_surgery;
|