Verify compression configuration on compression rollup

Add a check to verify compression settings for chunks to be rolled
up are identical.
This commit is contained in:
Sven Klemm 2024-01-25 14:11:40 +01:00 committed by Sven Klemm
parent 4934941f75
commit 83ff9662dc
7 changed files with 226 additions and 0 deletions

View File

@ -4,10 +4,14 @@
* LICENSE-APACHE for a copy of the license.
*/
#include <postgres.h>
#include <catalog/pg_collation.h>
#include <catalog/pg_type.h>
#include <fmgr.h>
#include <utils/array.h>
#include <utils/builtins.h>
#include <utils/fmgroids.h>
#include <compat/compat.h>
#include <debug_assert.h>
#include "array_utils.h"
@ -29,6 +33,26 @@ ts_array_length(ArrayType *arr)
return ARR_DIMS(arr)[0];
}
extern TSDLLEXPORT bool
ts_array_equal(ArrayType *left, ArrayType *right)
{
/* Quick exit if both are NULL or point to same thing. */
if (left == right)
return true;
if (left == NULL || right == NULL)
return false;
Assert(left != NULL && right != NULL && ARR_NDIM(left) == 1 && ARR_NDIM(right) == 1);
Datum result = OidFunctionCall2Coll(F_ARRAY_EQ,
DEFAULT_COLLATION_OID,
PointerGetDatum(left),
PointerGetDatum(right));
return DatumGetBool(result);
}
extern TSDLLEXPORT bool
ts_array_is_member(ArrayType *arr, const char *name)
{

View File

@ -18,6 +18,7 @@
*/
extern TSDLLEXPORT int ts_array_length(ArrayType *arr);
extern TSDLLEXPORT bool ts_array_equal(ArrayType *left, ArrayType *right);
extern TSDLLEXPORT bool ts_array_is_member(ArrayType *arr, const char *name);
extern TSDLLEXPORT int ts_array_position(ArrayType *arr, const char *name);

View File

@ -19,6 +19,15 @@ static ScanTupleResult compression_settings_tuple_update(TupleInfo *ti, void *da
static HeapTuple compression_settings_formdata_make_tuple(const FormData_compression_settings *fd,
TupleDesc desc);
bool
ts_compression_settings_equal(const CompressionSettings *left, const CompressionSettings *right)
{
return ts_array_equal(left->fd.segmentby, right->fd.segmentby) &&
ts_array_equal(left->fd.orderby, right->fd.orderby) &&
ts_array_equal(left->fd.orderby_desc, right->fd.orderby_desc) &&
ts_array_equal(left->fd.orderby_nullsfirst, right->fd.orderby_nullsfirst);
}
CompressionSettings *
ts_compression_settings_materialize(Oid ht_relid, Oid dst_relid)
{

View File

@ -23,6 +23,8 @@ TSDLLEXPORT CompressionSettings *ts_compression_settings_create(Oid relid, Array
TSDLLEXPORT CompressionSettings *ts_compression_settings_get(Oid relid);
TSDLLEXPORT CompressionSettings *ts_compression_settings_materialize(Oid ht_relid, Oid dst_relid);
TSDLLEXPORT bool ts_compression_settings_delete(Oid relid);
TSDLLEXPORT bool ts_compression_settings_equal(const CompressionSettings *left,
const CompressionSettings *right);
TSDLLEXPORT int ts_compression_settings_update(CompressionSettings *settings);

View File

@ -385,6 +385,13 @@ find_chunk_to_merge_into(Hypertable *ht, Chunk *current_chunk)
compressed_chunk_interval + current_chunk_interval > max_chunk_interval)
return NULL;
/* Get reloid of the previous compressed chunk */
Oid prev_comp_reloid = ts_chunk_get_relid(previous_chunk->fd.compressed_chunk_id, false);
CompressionSettings *prev_comp_settings = ts_compression_settings_get(prev_comp_reloid);
CompressionSettings *ht_comp_settings = ts_compression_settings_get(ht->main_table_relid);
if (!ts_compression_settings_equal(ht_comp_settings, prev_comp_settings))
return NULL;
return previous_chunk;
}

View File

@ -659,3 +659,132 @@ SELECT count(*) FROM test8 WHERE series_id = 1;
481
(1 row)
-- Verify rollup is prevented when compression settings differ
CREATE TABLE test9(time TIMESTAMPTZ NOT NULL, value DOUBLE PRECISION NOT NULL, series_id BIGINT NOT NULL);
SELECT create_hypertable('test9', 'time', chunk_time_interval => INTERVAL '1 h');
create_hypertable
---------------------
(17,public,test9,t)
(1 row)
ALTER TABLE test9 set (timescaledb.compress,
timescaledb.compress_segmentby = 'series_id',
timescaledb.compress_orderby = 'time',
timescaledb.compress_chunk_time_interval = '1 day');
-- create chunk and compress
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 00:00:00'::TIMESTAMPTZ, 1, 1;
SELECT compress_chunk(show_chunks('test9'), true);
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
(1 row)
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 01:00:00'::TIMESTAMPTZ, 1, 1;
-- should be 2 chunk before rollup
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 01:00:00 2020 PST
test9 | Wed Jan 01 01:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
(2 rows)
SELECT compress_chunk(show_chunks('test9'), true);
NOTICE: chunk "_hyper_17_320_chunk" is already compressed
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
_timescaledb_internal._hyper_17_320_chunk
(2 rows)
-- should be 1 chunk because of rollup
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
(1 row)
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 02:00:00'::TIMESTAMPTZ, 1, 1;
-- should be 2 chunks again
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
test9 | Wed Jan 01 02:00:00 2020 PST | Wed Jan 01 03:00:00 2020 PST
(2 rows)
ALTER TABLE test9 SET (timescaledb.compress_segmentby = '');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
NOTICE: chunk "_hyper_17_320_chunk" is already compressed
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
_timescaledb_internal._hyper_17_323_chunk
(2 rows)
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
test9 | Wed Jan 01 02:00:00 2020 PST | Wed Jan 01 03:00:00 2020 PST
(2 rows)
ROLLBACK;
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time DESC');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
NOTICE: chunk "_hyper_17_320_chunk" is already compressed
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
_timescaledb_internal._hyper_17_323_chunk
(2 rows)
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
test9 | Wed Jan 01 02:00:00 2020 PST | Wed Jan 01 03:00:00 2020 PST
(2 rows)
ROLLBACK;
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time NULLS FIRST');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
NOTICE: chunk "_hyper_17_320_chunk" is already compressed
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
_timescaledb_internal._hyper_17_323_chunk
(2 rows)
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 02:00:00 2020 PST
test9 | Wed Jan 01 02:00:00 2020 PST | Wed Jan 01 03:00:00 2020 PST
(2 rows)
ROLLBACK;
-- reset back to original settings
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
NOTICE: chunk "_hyper_17_320_chunk" is already compressed
compress_chunk
-------------------------------------------
_timescaledb_internal._hyper_17_320_chunk
_timescaledb_internal._hyper_17_320_chunk
(2 rows)
-- should be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
hypertable_name | range_start | range_end
-----------------+------------------------------+------------------------------
test9 | Wed Jan 01 00:00:00 2020 PST | Wed Jan 01 03:00:00 2020 PST
(1 row)
ROLLBACK;

View File

@ -233,3 +233,57 @@ SET enable_seqscan TO OFF;
SET enable_bitmapscan TO ON;
SELECT count(*) FROM test8 WHERE series_id = 1;
-- Verify rollup is prevented when compression settings differ
CREATE TABLE test9(time TIMESTAMPTZ NOT NULL, value DOUBLE PRECISION NOT NULL, series_id BIGINT NOT NULL);
SELECT create_hypertable('test9', 'time', chunk_time_interval => INTERVAL '1 h');
ALTER TABLE test9 set (timescaledb.compress,
timescaledb.compress_segmentby = 'series_id',
timescaledb.compress_orderby = 'time',
timescaledb.compress_chunk_time_interval = '1 day');
-- create chunk and compress
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 00:00:00'::TIMESTAMPTZ, 1, 1;
SELECT compress_chunk(show_chunks('test9'), true);
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 01:00:00'::TIMESTAMPTZ, 1, 1;
-- should be 2 chunk before rollup
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
SELECT compress_chunk(show_chunks('test9'), true);
-- should be 1 chunk because of rollup
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
INSERT INTO test9 (time, series_id, value) SELECT '2020-01-01 02:00:00'::TIMESTAMPTZ, 1, 1;
-- should be 2 chunks again
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
ALTER TABLE test9 SET (timescaledb.compress_segmentby = '');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
ROLLBACK;
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time DESC');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
ROLLBACK;
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time NULLS FIRST');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
-- should not be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
ROLLBACK;
-- reset back to original settings
ALTER TABLE test9 SET (timescaledb.compress_segmentby = 'series_id', timescaledb.compress_orderby = 'time');
BEGIN;
SELECT compress_chunk(show_chunks('test9'), true);
-- should be rolled up
SELECT hypertable_name, range_start, range_end FROM timescaledb_information.chunks WHERE hypertable_name = 'test9' ORDER BY 2;
ROLLBACK;