Skip to content

Commit 5252684

Browse files
committed
Propagate vacuum to compressed relation when running on chunk
When VACUUM or ANALYZE was run on a single chunk the compressed relation belonging to that chunk was not processed. Add the compressed relation to the list of relations to vacuum when the target is a compressed chunk.
1 parent 5ebc0fa commit 5252684

4 files changed

Lines changed: 80 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixes: #10286 Propagate VACUUM on a chunk to the compressed relation when running on chunk directly
2+
Thanks: @h0rn3t for reporting a problem with VACUUM not propagating to the compressed relation

src/process_utility.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,23 @@ process_vacuum(ProcessUtilityArgs *args)
12821282
ctx.ht_vacuum_rel = vacuum_rel;
12831283
foreach_chunk(ht, add_chunk_to_vacuum, &ctx, false);
12841284
}
1285+
else
1286+
{
1287+
/* VACUUM targets a chunk directly. */
1288+
Chunk *chunk = ts_chunk_get_by_relid(table_relid, false);
1289+
if (chunk && ts_chunk_is_compressed(chunk))
1290+
{
1291+
Oid compressed_relid = ts_relation_get_compressed_relid(chunk->fd.relid);
1292+
/* Compressed chunk might be missing due to concurrent operations */
1293+
if (OidIsValid(compressed_relid))
1294+
{
1295+
ctx.chunk_rels =
1296+
lappend(ctx.chunk_rels,
1297+
makeVacuumRelation(NULL, compressed_relid, NIL));
1298+
}
1299+
}
1300+
register_chunk_for_rebuild_if_needed(table_relid, &ctx);
1301+
}
12851302
}
12861303
vacuum_rels = lappend(vacuum_rels, vacuum_rel);
12871304
}

tsl/test/expected/vacuum.out

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,35 @@ DROP FUNCTION cagg_analyze_count_analyzed(name);
300300
DROP MATERIALIZED VIEW cagg_analyze_view;
301301
NOTICE: drop cascades to table _timescaledb_internal._hyper_6_9_chunk
302302
DROP TABLE cagg_analyze_src;
303+
-- VACUUM FULL on an individual chunk should also rewrite the underlying compressed relation
304+
-- VACUUM FULL assigns a new relfilenode, so we use that as a proxy for the
305+
-- compressed relation actually being processed.
306+
CREATE TABLE vacuum_chunk_test(time timestamptz NOT NULL, device int, value float);
307+
SELECT create_hypertable('vacuum_chunk_test', 'time', chunk_time_interval => interval '1 day');
308+
create_hypertable
309+
--------------------------------
310+
(7,public,vacuum_chunk_test,t)
311+
312+
INSERT INTO vacuum_chunk_test
313+
SELECT '2024-01-01'::timestamptz + (i || ' minute')::interval, i % 4, i::float
314+
FROM generate_series(0, 5000) i;
315+
ALTER TABLE vacuum_chunk_test SET (timescaledb.compress, timescaledb.compress_segmentby = 'device');
316+
SELECT count(compress_chunk(ch)) FROM show_chunks('vacuum_chunk_test') ch;
317+
count
318+
-------
319+
4
320+
321+
SELECT ch AS chunk FROM show_chunks('vacuum_chunk_test') ch ORDER BY ch LIMIT 1 \gset
322+
SELECT cs.compress_relid::oid AS compressed_relid
323+
FROM _timescaledb_catalog.compression_settings cs
324+
WHERE cs.relid = :'chunk'::regclass \gset
325+
SELECT relfilenode AS compressed_relfilenode_before
326+
FROM pg_class WHERE oid = :compressed_relid \gset
327+
VACUUM FULL :chunk;
328+
SELECT relfilenode <> :compressed_relfilenode_before AS compressed_rel_rewritten
329+
FROM pg_class WHERE oid = :compressed_relid;
330+
compressed_rel_rewritten
331+
--------------------------
332+
t
333+
334+
DROP TABLE vacuum_chunk_test;

tsl/test/sql/vacuum.sql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,32 @@ WHERE parent.hypertable_id = (SELECT mat_hypertable_id
230230
DROP FUNCTION cagg_analyze_count_analyzed(name);
231231
DROP MATERIALIZED VIEW cagg_analyze_view;
232232
DROP TABLE cagg_analyze_src;
233+
234+
-- VACUUM FULL on an individual chunk should also rewrite the underlying compressed relation
235+
-- VACUUM FULL assigns a new relfilenode, so we use that as a proxy for the
236+
-- compressed relation actually being processed.
237+
CREATE TABLE vacuum_chunk_test(time timestamptz NOT NULL, device int, value float);
238+
SELECT create_hypertable('vacuum_chunk_test', 'time', chunk_time_interval => interval '1 day');
239+
240+
INSERT INTO vacuum_chunk_test
241+
SELECT '2024-01-01'::timestamptz + (i || ' minute')::interval, i % 4, i::float
242+
FROM generate_series(0, 5000) i;
243+
244+
ALTER TABLE vacuum_chunk_test SET (timescaledb.compress, timescaledb.compress_segmentby = 'device');
245+
SELECT count(compress_chunk(ch)) FROM show_chunks('vacuum_chunk_test') ch;
246+
247+
SELECT ch AS chunk FROM show_chunks('vacuum_chunk_test') ch ORDER BY ch LIMIT 1 \gset
248+
249+
SELECT cs.compress_relid::oid AS compressed_relid
250+
FROM _timescaledb_catalog.compression_settings cs
251+
WHERE cs.relid = :'chunk'::regclass \gset
252+
253+
SELECT relfilenode AS compressed_relfilenode_before
254+
FROM pg_class WHERE oid = :compressed_relid \gset
255+
256+
VACUUM FULL :chunk;
257+
258+
SELECT relfilenode <> :compressed_relfilenode_before AS compressed_rel_rewritten
259+
FROM pg_class WHERE oid = :compressed_relid;
260+
261+
DROP TABLE vacuum_chunk_test;

0 commit comments

Comments
 (0)