Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions tsl/src/compression/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,15 @@ recompress_chunk_impl(Chunk *chunk, bool recompress)
return false;
}

if (!ts_guc_enable_optimizations)
{
ereport(NOTICE,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("segmentwise in-memory recompression functionality disabled, "
"set timescaledb.enable_optimizations to on")));
return false;
}

/* #9444: do not recompress when order by columns are nullable, do segmentwise
* decompress/compress instead. It is due to compression min/max metadata not handling
* NULLs. This restriction is lifted with first/last metadata index.
Expand Down Expand Up @@ -805,6 +814,15 @@ recompress_chunk_impl(Chunk *chunk, bool recompress)
return false;
}

if (!ts_guc_enable_optimizations)
{
ereport(DEBUG1,
(errcode(ERRCODE_WARNING),
errmsg("in-memory recompression functionality disabled, "
"set timescaledb.enable_optimizations to on")));
return false;
}

recompressed = recompress_chunk_in_memory_impl(chunk);
}

Expand Down Expand Up @@ -1023,6 +1041,11 @@ can_use_in_memory_rebuild(Chunk *chunk)
elog(DEBUG1, "timescaledb.enable_in_memory_recompression is disabled");
return false;
}
if (!ts_guc_enable_optimizations)
{
elog(DEBUG1, "timescaledb.enable_optimizations is disabled");
return false;
}

return true;
}
Expand Down
10 changes: 10 additions & 0 deletions tsl/src/compression/recompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS)
"enable it by first setting "
"timescaledb.enable_segmentwise_recompression to on")));
}

if (!ts_guc_enable_optimizations)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("segmentwise recompression functionality disabled, "
"enable it by first setting "
"timescaledb.enable_optimizations to on")));
}

CompressionSettings *settings = ts_compression_settings_get(uncompressed_relid);
if (!settings->fd.orderby)
{
Expand Down
26 changes: 22 additions & 4 deletions tsl/test/expected/rebuild_columnstore_tests.out
Original file line number Diff line number Diff line change
Expand Up @@ -251,20 +251,38 @@ SELECT _timescaledb_functions.unfreeze_chunk(chunk) FROM show_chunks('rebuild_er
----------------
t

SET timescaledb.enable_in_memory_recompression = false;
-- guc disabled, decompress/compress fallback
SET timescaledb.debug_compression_path_info = on;
SET timescaledb.enable_in_memory_recompression = false;
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
hypertable_name | chunk | compressed_chunk | status
-----------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_error | _timescaledb_internal._hyper_11_16_chunk | _timescaledb_internal.compress_hyper_12_17_chunk | {COMPRESSED}

CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
INFO: using tuplesort to scan rows from "_hyper_11_16_chunk" for converting to columnstore
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
hypertable_name | chunk | compressed_chunk | status
-----------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_error | _timescaledb_internal._hyper_11_16_chunk | _timescaledb_internal.compress_hyper_12_18_chunk | {COMPRESSED}

RESET timescaledb.enable_in_memory_recompression;
-- optimizations guc should disable too
SET timescaledb.enable_optimizations = false;
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
hypertable_name | chunk | compressed_chunk | status
-----------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_error | _timescaledb_internal._hyper_11_16_chunk | _timescaledb_internal.compress_hyper_12_18_chunk | {COMPRESSED}

CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
INFO: using tuplesort to scan rows from "_hyper_11_16_chunk" for converting to columnstore
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
hypertable_name | chunk | compressed_chunk | status
-----------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_error | _timescaledb_internal._hyper_11_16_chunk | _timescaledb_internal.compress_hyper_12_19_chunk | {COMPRESSED}

RESET timescaledb.enable_optimizations;
RESET timescaledb.debug_compression_path_info;
DROP TABLE rebuild_error CASCADE;
CREATE TABLE rebuild_no_orderby (col1 INT NOT NULL, device INT);
SELECT create_hypertable('rebuild_no_orderby', 'col1', chunk_time_interval => 10);
Expand All @@ -281,20 +299,20 @@ WARNING: disabling direct compress because of too small batch size
SELECT compress_chunk(chunk) FROM show_chunks('rebuild_no_orderby') chunk;
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_13_19_chunk
_timescaledb_internal._hyper_13_20_chunk

-- no orderby, decompress/compress fallback
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_no_orderby';
hypertable_name | chunk | compressed_chunk | status
--------------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_no_orderby | _timescaledb_internal._hyper_13_19_chunk | _timescaledb_internal.compress_hyper_14_20_chunk | {COMPRESSED}
rebuild_no_orderby | _timescaledb_internal._hyper_13_20_chunk | _timescaledb_internal.compress_hyper_14_21_chunk | {COMPRESSED}

SELECT chunk FROM show_chunks('rebuild_no_orderby') AS chunk LIMIT 1 \gset
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_no_orderby';
hypertable_name | chunk | compressed_chunk | status
--------------------+------------------------------------------+--------------------------------------------------+--------------
rebuild_no_orderby | _timescaledb_internal._hyper_13_19_chunk | _timescaledb_internal.compress_hyper_14_21_chunk | {COMPRESSED}
rebuild_no_orderby | _timescaledb_internal._hyper_13_20_chunk | _timescaledb_internal.compress_hyper_14_22_chunk | {COMPRESSED}

DROP TABLE rebuild_no_orderby CASCADE;
DROP VIEW chunk_status_view;
Expand Down
38 changes: 27 additions & 11 deletions tsl/test/expected/recompress_chunk_segmentwise.out
Original file line number Diff line number Diff line change
Expand Up @@ -627,12 +627,28 @@ 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
BEGIN;
SELECT compress_chunk(:'chunk_to_compress');
NOTICE: segmentwise in-memory recompression functionality disabled, set timescaledb.enable_segmentwise_recompression to on
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_22_24_chunk

ROLLBACK;
RESET timescaledb.enable_segmentwise_recompression;
-- Same when the optimizations GUC is off.
SET timescaledb.enable_optimizations 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_optimizations to on
\set ON_ERROR_STOP 1
SELECT compress_chunk(:'chunk_to_compress');
NOTICE: segmentwise in-memory recompression functionality disabled, set timescaledb.enable_optimizations to on
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_22_24_chunk

RESET timescaledb.enable_optimizations;
RESET timescaledb.enable_segmentwise_recompression;
--- Test behaviour of enable_exclusive_locking_recompression GUC
CREATE TABLE exclusive_test(time timestamptz not null, a int, b int, c int);
Expand Down Expand Up @@ -687,8 +703,8 @@ ORDER BY 1;
relname
-----------------------------------------------------------------
_hyper_22_24_chunk
compress_hyper_23_26_chunk
compress_hyper_23_26_chunk_a_b__ts_meta_v2_last_time__ts_me_idx
compress_hyper_23_27_chunk
compress_hyper_23_27_chunk_a_b__ts_meta_v2_last_time__ts_me_idx

ROLLBACK;
RESET timescaledb.enable_exclusive_locking_recompression;
Expand Down Expand Up @@ -743,7 +759,7 @@ SELECT DISTINCT _timescaledb_functions.chunk_status_text(chunk) FROM show_chunks
SELECT _timescaledb_functions.recompress_chunk_segmentwise(:'chunk_to_compress');
recompress_chunk_segmentwise
------------------------------------------
_timescaledb_internal._hyper_25_27_chunk
_timescaledb_internal._hyper_25_28_chunk

-- PARTIAL should be cleared (no more uncompressed rows).
-- UNORDERED must be preserved (segment a=2 still has unordered compressed data).
Expand All @@ -758,10 +774,10 @@ SELECT DISTINCT _timescaledb_functions.chunk_status_text(chunk) FROM show_chunks
SET timescaledb.debug_require_batch_sorted_merge = 'force';
EXPLAIN (COSTS OFF) SELECT a, time FROM segwise_unordered WHERE a = 2 ORDER BY a, time;
--- QUERY PLAN ---
Custom Scan (ColumnarScan) on _hyper_25_27_chunk
Custom Scan (ColumnarScan) on _hyper_25_28_chunk
-> Sort
Sort Key: compress_hyper_26_28_chunk._ts_meta_v2_first_time
-> Index Scan using compress_hyper_26_28_chunk_a__ts_meta_v2_first_time__ts_met_idx on compress_hyper_26_28_chunk
Sort Key: compress_hyper_26_29_chunk._ts_meta_v2_first_time
-> Index Scan using compress_hyper_26_29_chunk_a__ts_meta_v2_first_time__ts_met_idx on compress_hyper_26_29_chunk
Index Cond: (a = 2)

RESET timescaledb.debug_require_batch_sorted_merge;
Expand Down Expand Up @@ -799,7 +815,7 @@ CROSS JOIN generate_series(1, 10) t;
SELECT compress_chunk(c) FROM show_chunks('segwise_no_overlap') c;
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_27_29_chunk
_timescaledb_internal._hyper_27_30_chunk

-- Add rows for series_id = 50 (inside the existing batch's series_id range)
-- with ts outside the existing batch's ts range. Pre-fix, the matcher would
Expand All @@ -811,7 +827,7 @@ FROM generate_series(1, 500) t;
SELECT compress_chunk(c) FROM show_chunks('segwise_no_overlap') c;
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_27_29_chunk
_timescaledb_internal._hyper_27_30_chunk

-- Locate the compressed chunk for the metadata check.
SELECT cs.compress_relid AS comp_table_segwise
Expand Down Expand Up @@ -888,7 +904,7 @@ SELECT compress_chunk(c)
FROM show_chunks('segwise_uaf_scankeys') c;
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_29_31_chunk
_timescaledb_internal._hyper_29_32_chunk

INSERT INTO segwise_uaf_scankeys
SELECT '2024-01-01'::timestamptz + ((i + 1000) || 's')::interval + '1us'::interval,
Expand All @@ -903,7 +919,7 @@ SELECT compress_chunk(c)
FROM show_chunks('segwise_uaf_scankeys') c;
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_29_31_chunk
_timescaledb_internal._hyper_29_32_chunk

INSERT INTO segwise_uaf_scankeys
SELECT '2024-01-01'::timestamptz + ((i + 3000) || 's')::interval + '2us'::interval,
Expand All @@ -918,7 +934,7 @@ SELECT compress_chunk(c)
FROM show_chunks('segwise_uaf_scankeys') c; -- should not segfault
compress_chunk
------------------------------------------
_timescaledb_internal._hyper_29_31_chunk
_timescaledb_internal._hyper_29_32_chunk

RESET maintenance_work_mem;
DROP TABLE segwise_uaf_scankeys;
Expand Down
15 changes: 14 additions & 1 deletion tsl/test/sql/rebuild_columnstore_tests.sql
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,25 @@ SELECT _timescaledb_functions.freeze_chunk(chunk) FROM show_chunks('rebuild_erro
-- frozen notice
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
SELECT _timescaledb_functions.unfreeze_chunk(chunk) FROM show_chunks('rebuild_error') AS chunk;
SET timescaledb.enable_in_memory_recompression = false;

-- guc disabled, decompress/compress fallback
SET timescaledb.debug_compression_path_info = on;

SET timescaledb.enable_in_memory_recompression = false;
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
RESET timescaledb.enable_in_memory_recompression;

-- optimizations guc should disable too
SET timescaledb.enable_optimizations = false;
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
SELECT * FROM chunk_status_view WHERE hypertable_name = 'rebuild_error';
RESET timescaledb.enable_optimizations;

RESET timescaledb.debug_compression_path_info;

DROP TABLE rebuild_error CASCADE;

CREATE TABLE rebuild_no_orderby (col1 INT NOT NULL, device INT);
Expand Down
12 changes: 12 additions & 0 deletions tsl/test/sql/recompress_chunk_segmentwise.sql
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,22 @@ SET timescaledb.enable_segmentwise_recompression TO OFF;
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
BEGIN;
SELECT compress_chunk(:'chunk_to_compress');
ROLLBACK;

RESET timescaledb.enable_segmentwise_recompression;

-- Same when the optimizations GUC is off.
SET timescaledb.enable_optimizations TO OFF;
\set ON_ERROR_STOP 0
SELECT _timescaledb_functions.recompress_chunk_segmentwise(:'chunk_to_compress');
\set ON_ERROR_STOP 1
SELECT compress_chunk(:'chunk_to_compress');
RESET timescaledb.enable_optimizations;
RESET timescaledb.enable_segmentwise_recompression;


--- Test behaviour of enable_exclusive_locking_recompression GUC
CREATE TABLE exclusive_test(time timestamptz not null, a int, b int, c int);
SELECT create_hypertable('exclusive_test', by_range('time', INTERVAL '1 day'));
Expand Down
Loading