1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
# Test that pruning and vacuuming pay attention to concurrent sessions
# in the right way. For normal relations that means that rows cannot
# be pruned away if there's an older snapshot, in contrast to that
# temporary tables should nearly always be prunable.
#
# NB: Think hard before adding a test showing that rows in permanent
# tables get pruned - it's quite likely that it'd be racy, e.g. due to
# an autovacuum worker holding a snapshot.
setup {
CREATE OR REPLACE FUNCTION explain_json(p_query text)
RETURNS json
LANGUAGE plpgsql AS $$
DECLARE
v_ret json;
BEGIN
EXECUTE p_query INTO STRICT v_ret;
RETURN v_ret;
END;$$;
}
teardown {
DROP FUNCTION explain_json(text);
}
session lifeline
# Start a transaction, force a snapshot to be held
step ll_start
{
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT 1;
}
step ll_commit { COMMIT; }
session pruner
setup
{
SET enable_seqscan = false;
SET enable_indexscan = false;
SET enable_bitmapscan = false;
}
step pruner_create_temp
{
CREATE TEMPORARY TABLE horizons_tst (data int unique) WITH (autovacuum_enabled = off);
INSERT INTO horizons_tst(data) VALUES(1),(2);
}
step pruner_create_perm
{
CREATE TABLE horizons_tst (data int unique) WITH (autovacuum_enabled = off);
INSERT INTO horizons_tst(data) VALUES(1),(2);
}
# Temp tables cannot be dropped in the teardown, so just always do so
# as part of the permutation
step pruner_drop
{
DROP TABLE horizons_tst;
}
step pruner_delete
{
DELETE FROM horizons_tst;
}
step pruner_begin { BEGIN; }
step pruner_commit { COMMIT; }
step pruner_vacuum
{
VACUUM horizons_tst;
}
# Show the heap fetches of an ordered index-only-scan (other plans
# have been forbidden above) - that tells us how many non-killed leaf
# entries there are.
step pruner_query
{
SELECT explain_json($$
EXPLAIN (FORMAT json, BUFFERS, ANALYZE)
SELECT * FROM horizons_tst ORDER BY data;$$)->0->'Plan'->'Heap Fetches';
}
# Verify that the query plan still is an IOS
step pruner_query_plan
{
EXPLAIN (COSTS OFF) SELECT * FROM horizons_tst ORDER BY data;
}
# Show that with a permanent relation deleted rows cannot be pruned
# away if there's a concurrent session still seeing the rows.
permutation
pruner_create_perm
ll_start
pruner_query_plan
# Run query that could do pruning twice, first has chance to prune,
# second would not perform heap fetches if first query did.
pruner_query
pruner_query
pruner_delete
pruner_query
pruner_query
ll_commit
pruner_drop
# Show that with a temporary relation deleted rows can be pruned away,
# even if there's a concurrent session with a snapshot from before the
# deletion. That's safe because the session with the older snapshot
# cannot access the temporary table.
permutation
pruner_create_temp
ll_start
pruner_query_plan
pruner_query
pruner_query
pruner_delete
pruner_query
pruner_query
ll_commit
pruner_drop
# Verify that pruning in temporary relations doesn't remove rows still
# visible in the current session
permutation
pruner_create_temp
ll_start
pruner_query
pruner_query
pruner_begin
pruner_delete
pruner_query
pruner_query
ll_commit
pruner_commit
pruner_drop
# Show that vacuum cannot remove deleted rows still visible to another
# session's snapshot, when accessing a permanent table.
permutation
pruner_create_perm
ll_start
pruner_query
pruner_query
pruner_delete
pruner_vacuum
pruner_query
pruner_query
ll_commit
pruner_drop
# Show that vacuum can remove deleted rows still visible to another
# session's snapshot, when accessing a temporary table.
permutation
pruner_create_temp
ll_start
pruner_query
pruner_query
pruner_delete
pruner_vacuum
pruner_query
pruner_query
ll_commit
pruner_drop
|