From 7c78fad96483f9cb1250cf709c71e5e59313e239 Mon Sep 17 00:00:00 2001 From: Keyur Panchal Date: Mon, 4 Nov 2024 07:24:52 -0700 Subject: [PATCH] Add GUC for segmentwise recompression (#7413) Add GUC option to enable or disable segmentwise recompression. If disabled, then a full recompression is done instead when recompression is attempted through `compress_chunk`. If `recompress_chunk_segmentwise` is used when GUC is disabled, then an error is thrown. Closes #7381. --- .unreleased/pr_7413 | 1 + src/guc.c | 12 +++++++ src/guc.h | 1 + tsl/src/compression/api.c | 18 +++++++++- .../expected/recompress_chunk_segmentwise.out | 33 +++++++++++++++++++ tsl/test/sql/recompress_chunk_segmentwise.sql | 18 ++++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 .unreleased/pr_7413 diff --git a/.unreleased/pr_7413 b/.unreleased/pr_7413 new file mode 100644 index 00000000000..53f2a223bae --- /dev/null +++ b/.unreleased/pr_7413 @@ -0,0 +1 @@ +Implements: #7413: Add GUC for segmentwise recompression. diff --git a/src/guc.c b/src/guc.c index 7786505a49c..c4c52dd7b8d 100644 --- a/src/guc.c +++ b/src/guc.c @@ -139,6 +139,7 @@ TSDLLEXPORT bool ts_guc_enable_compression_indexscan = false; TSDLLEXPORT bool ts_guc_enable_bulk_decompression = true; TSDLLEXPORT bool ts_guc_auto_sparse_indexes = true; bool ts_guc_enable_chunk_skipping = false; +TSDLLEXPORT bool ts_guc_enable_segmentwise_recompression = true; /* Enable of disable columnar scans for columnar-oriented storage engines. If * disabled, regular sequence scans will be used instead. */ @@ -703,6 +704,17 @@ _guc_init(void) NULL, NULL); + DefineCustomBoolVariable(MAKE_EXTOPTION("enable_segmentwise_recompression"), + "Enable segmentwise recompression functionality", + "Enable segmentwise recompression", + &ts_guc_enable_segmentwise_recompression, + true, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + /* * Define the limit on number of invalidation-based refreshes we allow per * refresh call. If this limit is exceeded, fall back to a single refresh that diff --git a/src/guc.h b/src/guc.h index fa3503f6cea..7c0fb5e0606 100644 --- a/src/guc.h +++ b/src/guc.h @@ -52,6 +52,7 @@ extern bool ts_guc_enable_tss_callbacks; extern TSDLLEXPORT bool ts_guc_enable_delete_after_compression; extern TSDLLEXPORT bool ts_guc_enable_merge_on_cagg_refresh; extern bool ts_guc_enable_chunk_skipping; +extern TSDLLEXPORT bool ts_guc_enable_segmentwise_recompression; #ifdef USE_TELEMETRY typedef enum TelemetryLevel diff --git a/tsl/src/compression/api.c b/tsl/src/compression/api.c index dcb5d769077..911a6a15fb3 100644 --- a/tsl/src/compression/api.c +++ b/tsl/src/compression/api.c @@ -8,6 +8,7 @@ * compress and decompress chunks */ #include +#include "guc.h" #include #include #include @@ -919,12 +920,19 @@ tsl_compress_chunk_wrapper(Chunk *chunk, bool if_not_compressed, bool recompress return uncompressed_chunk_id; } - if (ts_chunk_is_partial(chunk) && get_compressed_chunk_index_for_recompression(chunk)) + if (ts_guc_enable_segmentwise_recompression && ts_chunk_is_partial(chunk) && + get_compressed_chunk_index_for_recompression(chunk)) { uncompressed_chunk_id = recompress_chunk_segmentwise_impl(chunk); } else { + if (!ts_guc_enable_segmentwise_recompression) + elog(NOTICE, + "segmentwise recompression is disabled, performing full recompression on " + "chunk \"%s.%s\"", + NameStr(chunk->fd.schema_name), + NameStr(chunk->fd.table_name)); decompress_chunk_impl(chunk, false); compress_chunk_impl(chunk->hypertable_relid, chunk->table_id); } @@ -1257,6 +1265,14 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS) } else { + if (!ts_guc_enable_segmentwise_recompression) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("segmentwise recompression functionality disabled, " + "enable it by first setting " + "timescaledb.enable_segmentwise_recompression to on"))); + } uncompressed_chunk_id = recompress_chunk_segmentwise_impl(chunk); } diff --git a/tsl/test/expected/recompress_chunk_segmentwise.out b/tsl/test/expected/recompress_chunk_segmentwise.out index d984b713a93..db795bbe76f 100644 --- a/tsl/test/expected/recompress_chunk_segmentwise.out +++ b/tsl/test/expected/recompress_chunk_segmentwise.out @@ -593,3 +593,36 @@ select * from :compressed_chunk_name; 2 | 1 | | Sat Jan 01 01:00:00 2022 PST | Sat Jan 01 01:00:00 2022 PST | BAAAAneAR/JEAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAA7gAE7wCP5IgAAATvAI/kh/8= | BAEAAAAAAAAABAAAAAAAAAAEAAAAAQAAAAEAAAAAAAAABAAAAAAAAAAIAAAAAgAAAAEAAAAAAAAAAQAAAAAAAAAB (5 rows) +--- Test behaviour when enable_segmentwise_recompression GUC if OFF +CREATE TABLE guc_test(time timestamptz not null, a int, b int, c int); +SELECT create_hypertable('guc_test', by_range('time', INTERVAL '1 day')); + create_hypertable +------------------- + (18,t) +(1 row) + +ALTER TABLE guc_test set (timescaledb.compress, timescaledb.compress_segmentby = 'a, b'); +NOTICE: default order by for hypertable "guc_test" is set to ""time" DESC" +INSERT INTO guc_test VALUES ('2024-10-30 14:04:00.501519-06'::timestamptz, 1, 1, 1); +SELECT show_chunks as chunk_to_compress FROM show_chunks('guc_test') LIMIT 1 \gset +SELECT compress_chunk(:'chunk_to_compress'); + compress_chunk +------------------------------------------ + _timescaledb_internal._hyper_18_20_chunk +(1 row) + +INSERT INTO guc_test VALUES ('2024-10-30 14:14:00.501519-06'::timestamptz, 1, 1, 2); +-- When GUC is OFF, recompress function should throw an error +SET timescaledb.enable_segmentwise_recompression TO OFF; +\set ON_ERROR_STOP 0 +SELECT _timescaledb_functions.recompress_chunk_segmentwise(:'chunk_to_compress'); +ERROR: segmentwise recompression functionality disabled, enable it by first setting timescaledb.enable_segmentwise_recompression to on +\set ON_ERROR_STOP 1 +-- When GUC is OFF, entire chunk should be fully uncompressed and compressed instead +SELECT compress_chunk(:'chunk_to_compress'); +NOTICE: segmentwise recompression is disabled, performing full recompression on chunk "_timescaledb_internal._hyper_18_20_chunk" + compress_chunk +------------------------------------------ + _timescaledb_internal._hyper_18_20_chunk +(1 row) + diff --git a/tsl/test/sql/recompress_chunk_segmentwise.sql b/tsl/test/sql/recompress_chunk_segmentwise.sql index 4e540212275..3c6a43ec9c0 100644 --- a/tsl/test/sql/recompress_chunk_segmentwise.sql +++ b/tsl/test/sql/recompress_chunk_segmentwise.sql @@ -290,3 +290,21 @@ select * from :compressed_chunk_name; insert into nullseg_many values (:'start_time', 1, NULL, NULL); SELECT compress_chunk(:'chunk_to_compress'); select * from :compressed_chunk_name; + +--- Test behaviour when enable_segmentwise_recompression GUC if OFF +CREATE TABLE guc_test(time timestamptz not null, a int, b int, c int); +SELECT create_hypertable('guc_test', by_range('time', INTERVAL '1 day')); + +ALTER TABLE guc_test set (timescaledb.compress, timescaledb.compress_segmentby = 'a, b'); +INSERT INTO guc_test VALUES ('2024-10-30 14:04:00.501519-06'::timestamptz, 1, 1, 1); +SELECT show_chunks as chunk_to_compress FROM show_chunks('guc_test') LIMIT 1 \gset +SELECT compress_chunk(:'chunk_to_compress'); + +INSERT INTO guc_test VALUES ('2024-10-30 14:14:00.501519-06'::timestamptz, 1, 1, 2); +-- When GUC is OFF, recompress function should throw an error +SET timescaledb.enable_segmentwise_recompression TO OFF; +\set ON_ERROR_STOP 0 +SELECT _timescaledb_functions.recompress_chunk_segmentwise(:'chunk_to_compress'); +\set ON_ERROR_STOP 1 +-- When GUC is OFF, entire chunk should be fully uncompressed and compressed instead +SELECT compress_chunk(:'chunk_to_compress');