Skip to content

Commit

Permalink
Add GUC for segmentwise recompression
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kpan2034 committed Oct 31, 2024
1 parent 76e3b27 commit 796d690
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 1 deletion.
1 change: 1 addition & 0 deletions .unreleased/pr_7413
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implements: #7413: Add GUC for segmentwise recompression.
12 changes: 12 additions & 0 deletions src/guc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/guc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 17 additions & 1 deletion tsl/src/compression/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* compress and decompress chunks
*/
#include <postgres.h>
#include "guc.h"
#include <access/tableam.h>
#include <access/xact.h>
#include <catalog/dependency.h>
Expand Down Expand Up @@ -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(DEBUG1,
"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);
}
Expand Down Expand Up @@ -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);
}

Expand Down
58 changes: 58 additions & 0 deletions tsl/test/expected/recompress_chunk_segmentwise.out
Original file line number Diff line number Diff line change
Expand Up @@ -593,3 +593,61 @@ 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
SET client_min_messages TO DEBUG;
SELECT compress_chunk(:'chunk_to_compress');
LOG: statement: SELECT compress_chunk('_timescaledb_internal._hyper_18_20_chunk');
DEBUG: capture_ExecutorStart - rtable #0: (null) (relid: 0)
DEBUG: segmentwise recompression is disabled, performing full recompression on chunk "_timescaledb_internal._hyper_18_20_chunk"
DEBUG: acquiring locks for decompressing "_timescaledb_internal._hyper_18_20_chunk"
DEBUG: locks acquired for decompressing "_timescaledb_internal._hyper_18_20_chunk"
DEBUG: finished decompressing 1 rows from "compress_hyper_19_21_chunk"
DEBUG: drop auto-cascades to type _timescaledb_internal.compress_hyper_19_21_chunk
DEBUG: drop auto-cascades to type _timescaledb_internal.compress_hyper_19_21_chunk[]
DEBUG: drop auto-cascades to toast table pg_toast.pg_toast_17376
DEBUG: drop auto-cascades to index pg_toast.pg_toast_17376_index
DEBUG: drop auto-cascades to index _timescaledb_internal.compress_hyper_19_21_chunk_a_b__ts_meta_min_1__ts_meta_max__idx
DEBUG: acquiring locks for compressing "_timescaledb_internal._hyper_18_20_chunk"
DEBUG: locks acquired for compressing "_timescaledb_internal._hyper_18_20_chunk"
DEBUG: building index "pg_toast_17384_index" on table "pg_toast_17384" serially
DEBUG: index "pg_toast_17384_index" can safely use deduplication
DEBUG: building index "compress_hyper_19_22_chunk_a_b__ts_meta_min_1__ts_meta_max__idx" on table "compress_hyper_19_22_chunk" serially
DEBUG: index "compress_hyper_19_22_chunk_a_b__ts_meta_min_1__ts_meta_max__idx" can safely use deduplication
DEBUG: adding index compress_hyper_19_22_chunk_a_b__ts_meta_min_1__ts_meta_max__idx ON _timescaledb_internal.compress_hyper_19_22_chunk USING BTREE(a, b, _ts_meta_min_1 DESC, _ts_meta_max_1 DESC, )
DEBUG: new compressed chunk "_timescaledb_internal.compress_hyper_19_22_chunk" created
DEBUG: using tuplesort to scan rows from "_hyper_18_20_chunk" for compression
DEBUG: finished compressing 2 rows from "_hyper_18_20_chunk"
DEBUG: building index "_hyper_18_20_chunk_guc_test_time_idx" on table "_hyper_18_20_chunk" serially
DEBUG: index "_hyper_18_20_chunk_guc_test_time_idx" can safely use deduplication
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_18_20_chunk
(1 row)

RESET client_min_messages;
LOG: statement: RESET client_min_messages;
20 changes: 20 additions & 0 deletions tsl/test/sql/recompress_chunk_segmentwise.sql
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,23 @@ 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
SET client_min_messages TO DEBUG;
SELECT compress_chunk(:'chunk_to_compress');
RESET client_min_messages;

0 comments on commit 796d690

Please sign in to comment.