diff --git a/.unreleased/pr_7412 b/.unreleased/pr_7412 new file mode 100644 index 00000000000..d978a7bc9d1 --- /dev/null +++ b/.unreleased/pr_7412 @@ -0,0 +1 @@ +Implements: #7412 Add GUC for hypercore_use_access_method default diff --git a/src/guc.c b/src/guc.c index 75d85420095..eb2f132a005 100644 --- a/src/guc.c +++ b/src/guc.c @@ -16,6 +16,7 @@ #include "guc.h" #include "hypertable_cache.h" #include "license_guc.h" + #ifdef USE_TELEMETRY #include "telemetry/telemetry.h" #endif @@ -139,6 +140,7 @@ bool ts_guc_enable_custom_hashagg = false; TSDLLEXPORT bool ts_guc_enable_compression_indexscan = false; TSDLLEXPORT bool ts_guc_enable_bulk_decompression = true; TSDLLEXPORT bool ts_guc_auto_sparse_indexes = true; +TSDLLEXPORT bool ts_guc_default_hypercore_use_access_method = false; bool ts_guc_enable_chunk_skipping = false; TSDLLEXPORT bool ts_guc_enable_segmentwise_recompression = true; @@ -1117,6 +1119,18 @@ _guc_init(void) /* show_hook= */ NULL); #endif + DefineCustomBoolVariable(MAKE_EXTOPTION("default_hypercore_use_access_method"), + gettext_noop("Enable to always use Hypercore TAM when compressing."), + gettext_noop("Sets the global default for using Hypercore TAM when " + "compressing chunks."), + &ts_guc_default_hypercore_use_access_method, + false, + /* context= */ PGC_USERSET, + /* flags= */ 0, + /* check_hook= */ NULL, + /* assign_hook= */ NULL, + /* show_hook= */ NULL); + /* register feature flags */ ts_feature_flag_add(FEATURE_HYPERTABLE); ts_feature_flag_add(FEATURE_HYPERTABLE_COMPRESSION); diff --git a/src/guc.h b/src/guc.h index 81e237dc28d..ad8f80decd7 100644 --- a/src/guc.h +++ b/src/guc.h @@ -11,6 +11,21 @@ #include "config.h" #include "export.h" +/* + * Decide if the access method should be used for compression, or if it is + * undefined. Used for parameter values to PostgreSQL functions and is a + * nullable boolean. + * + * Using explicit values of TRUE = 1 and FALSE = 0 since this enum is cast to + * boolean value in the code. + */ +typedef enum UseAccessMethod +{ + USE_AM_FALSE = 0, + USE_AM_TRUE = 1, + USE_AM_NULL = 2, +} UseAccessMethod; + #ifdef USE_TELEMETRY extern bool ts_telemetry_on(void); extern bool ts_function_telemetry_on(void); @@ -102,6 +117,7 @@ extern TSDLLEXPORT DebugRequireOption ts_guc_debug_require_vector_agg; extern TSDLLEXPORT bool ts_guc_debug_compression_path_info; extern TSDLLEXPORT bool ts_guc_enable_rowlevel_compression_locking; +extern TSDLLEXPORT bool ts_guc_default_hypercore_use_access_method; extern TSDLLEXPORT bool ts_guc_debug_require_batch_sorted_merge; @@ -121,4 +137,5 @@ typedef enum extern TSDLLEXPORT void ts_feature_flag_check(FeatureFlagType); extern TSDLLEXPORT Oid ts_guc_default_segmentby_fn_oid(void); extern TSDLLEXPORT Oid ts_guc_default_orderby_fn_oid(void); + extern TSDLLEXPORT bool ts_is_whitelisted_indexam(const char *amname); diff --git a/tsl/src/bgw_policy/compression_api.h b/tsl/src/bgw_policy/compression_api.h index 9d717ec7134..e4d82dea9d0 100644 --- a/tsl/src/bgw_policy/compression_api.h +++ b/tsl/src/bgw_policy/compression_api.h @@ -6,10 +6,11 @@ #pragma once #include -#include "compression/api.h" #include #include +#include "guc.h" + /* User-facing API functions */ extern Datum policy_compression_add(PG_FUNCTION_ARGS); extern Datum policy_compression_remove(PG_FUNCTION_ARGS); diff --git a/tsl/src/compression/api.c b/tsl/src/compression/api.c index 029f2ade7ec..bb615ded566 100644 --- a/tsl/src/compression/api.c +++ b/tsl/src/compression/api.c @@ -838,13 +838,23 @@ compress_hypercore(Chunk *chunk, bool rel_is_hypercore, UseAccessMethod useam, return relid; } +/* + * Check the value of the use_access_method argument and use the default value + * otherwise. + */ +static UseAccessMethod +check_useam(UseAccessMethod arg) +{ + return arg == USE_AM_NULL ? (UseAccessMethod) ts_guc_default_hypercore_use_access_method : arg; +} + Datum tsl_compress_chunk(PG_FUNCTION_ARGS) { Oid uncompressed_chunk_id = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); bool if_not_compressed = PG_ARGISNULL(1) ? true : PG_GETARG_BOOL(1); bool recompress = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2); - UseAccessMethod useam = PG_ARGISNULL(3) ? USE_AM_NULL : PG_GETARG_BOOL(3); + UseAccessMethod useam = check_useam(PG_ARGISNULL(3) ? USE_AM_NULL : PG_GETARG_BOOL(3)); ts_feature_flag_check(FEATURE_HYPERTABLE_COMPRESSION); diff --git a/tsl/src/compression/api.h b/tsl/src/compression/api.h index ab2b99a025f..44c8660da9f 100644 --- a/tsl/src/compression/api.h +++ b/tsl/src/compression/api.h @@ -11,21 +11,6 @@ #include "chunk.h" -/* - * Decide if the access method should be used for compression, or if it is - * undefined. Used for parameter values to PostgreSQL functions and is a - * nullable boolean. - * - * Using explicit values of TRUE = 1 and FALSE = 0 since this enum is cast to - * boolean value in the code. - */ -typedef enum UseAccessMethod -{ - USE_AM_FALSE = 0, - USE_AM_TRUE = 1, - USE_AM_NULL = 2, -} UseAccessMethod; - extern Datum tsl_create_compressed_chunk(PG_FUNCTION_ARGS); extern Datum tsl_compress_chunk(PG_FUNCTION_ARGS); extern Datum tsl_decompress_chunk(PG_FUNCTION_ARGS); diff --git a/tsl/test/expected/hypercore.out b/tsl/test/expected/hypercore.out index 03e5983b7dd..985be96d57c 100644 --- a/tsl/test/expected/hypercore.out +++ b/tsl/test/expected/hypercore.out @@ -521,6 +521,7 @@ SELECT sum(_ts_meta_count) FROM :cchunk; CALL recompress_chunk(:'chunk'); WARNING: procedure public.recompress_chunk(regclass,boolean) is deprecated and the functionality is now included in public.compress_chunk. this compatibility function will be removed in a future version. +NOTICE: cannot compress hypercore "_hyper_1_1_chunk" using heap, recompressing instead -- Data should be returned even after recompress, but now from the -- compressed relation. Still using index scan. EXPLAIN (verbose, costs off) @@ -575,6 +576,7 @@ SELECT * FROM :chunk WHERE time = '2022-06-01 00:06:15'::timestamptz; -- Can't recompress twice without new non-compressed rows CALL recompress_chunk(:'chunk'); WARNING: procedure public.recompress_chunk(regclass,boolean) is deprecated and the functionality is now included in public.compress_chunk. this compatibility function will be removed in a future version. +NOTICE: cannot compress hypercore "_hyper_1_1_chunk" using heap, recompressing instead NOTICE: chunk "_hyper_1_1_chunk" is already compressed \set ON_ERROR_STOP 1 -- Compressed count after recompression diff --git a/tsl/test/expected/hypercore_create.out b/tsl/test/expected/hypercore_create.out index 4e56b1486e4..78ed60ec070 100644 --- a/tsl/test/expected/hypercore_create.out +++ b/tsl/test/expected/hypercore_create.out @@ -691,6 +691,7 @@ select ctid from :chunk where created_at = '2022-06-01 10:01' and device_id = 6; (1 row) select compress_chunk(:'chunk'); +NOTICE: cannot compress hypercore "_hyper_1_1_chunk" using heap, recompressing instead compress_chunk ---------------------------------------- _timescaledb_internal._hyper_1_1_chunk @@ -921,3 +922,60 @@ select * from rides order by pickup_datetime; 745233436676 | Fri Jan 01 00:00:03 2016 PST | Fri Jan 01 00:11:14 2016 PST | 1 | 6.00 | -73.947151184082031 | 40.791046142578125 | 1 | -73.920768737792969 | 40.865577697753906 | 2 | 9 | 0.5 | 0.5 | 0 | 0 | 0.3 | 19.3 (3 rows) +-- All these are valid methods to set the default +show timescaledb.default_hypercore_use_access_method; + timescaledb.default_hypercore_use_access_method +------------------------------------------------- + off +(1 row) + +set timescaledb.default_hypercore_use_access_method to on; +set timescaledb.default_hypercore_use_access_method to off; +set timescaledb.default_hypercore_use_access_method to true; +set timescaledb.default_hypercore_use_access_method to false; +set timescaledb.default_hypercore_use_access_method to yes; +set timescaledb.default_hypercore_use_access_method to no; +set timescaledb.default_hypercore_use_access_method to 0; +set timescaledb.default_hypercore_use_access_method to 1; +show timescaledb.default_hypercore_use_access_method; + timescaledb.default_hypercore_use_access_method +------------------------------------------------- + on +(1 row) + +-- This should unset the value +reset timescaledb.default_hypercore_use_access_method; +show timescaledb.default_hypercore_use_access_method; + timescaledb.default_hypercore_use_access_method +------------------------------------------------- + off +(1 row) + +-- Using GUC should compress using the hyperstore +set timescaledb.default_hypercore_use_access_method to on; +create table test5 (time timestamptz not null, device int, temp float); +select created from create_hypertable('test5', 'time'); + created +--------- + t +(1 row) + +insert into test5 values ('2022-06-01', 1, 1.0), ('2022-08-01', 1, 1.0); +select ch as chunk from show_chunks('test5') ch limit 1 \gset +alter table test5 set (timescaledb.compress); +WARNING: there was some uncertainty picking the default segment by for the hypertable: You do not have any indexes on columns that can be used for segment_by and thus we are not using segment_by for compression. Please make sure you are not missing any indexes +NOTICE: default segment by for hypertable "test5" is set to "" +NOTICE: default order by for hypertable "test5" is set to ""time" DESC" +select compress_chunk(:'chunk'); + compress_chunk +------------------------------------------ + _timescaledb_internal._hyper_10_46_chunk +(1 row) + +select * from amrels where relparent = 'test5'::regclass; + rel | amname | relparent +------------------------------------------+-----------+----------- + _timescaledb_internal._hyper_10_46_chunk | hypercore | test5 + _timescaledb_internal._hyper_10_47_chunk | heap | test5 +(2 rows) + diff --git a/tsl/test/expected/hypercore_vacuum.out b/tsl/test/expected/hypercore_vacuum.out index eab589787e3..0f2382b1412 100644 --- a/tsl/test/expected/hypercore_vacuum.out +++ b/tsl/test/expected/hypercore_vacuum.out @@ -227,6 +227,7 @@ insert into hystable (time, location, device, temp) values ('2022-06-01 00:01', 1, 1, 1.0); -- Recompress to get data back into compressed form select compress_chunk(:'hystable_chunk'); +NOTICE: cannot compress hypercore "_hyper_1_2_chunk" using heap, recompressing instead compress_chunk ---------------------------------------- _timescaledb_internal._hyper_1_2_chunk @@ -310,6 +311,7 @@ select tuple_count from pgstattuple(:'hystable_device_chunk_idx'); -- rebuild indexes. It will optimize the structure of the index and -- thus reduce the number of index tuples select compress_chunk(:'hystable_chunk'); +NOTICE: cannot compress hypercore "_hyper_1_2_chunk" using heap, recompressing instead compress_chunk ---------------------------------------- _timescaledb_internal._hyper_1_2_chunk diff --git a/tsl/test/sql/hypercore_create.sql b/tsl/test/sql/hypercore_create.sql index 9b0bd02ae41..db179cd4488 100644 --- a/tsl/test/sql/hypercore_create.sql +++ b/tsl/test/sql/hypercore_create.sql @@ -446,3 +446,30 @@ analyze rides; explain (costs off) select * from rides order by pickup_datetime; select * from rides order by pickup_datetime; + +-- All these are valid methods to set the default +show timescaledb.default_hypercore_use_access_method; +set timescaledb.default_hypercore_use_access_method to on; +set timescaledb.default_hypercore_use_access_method to off; +set timescaledb.default_hypercore_use_access_method to true; +set timescaledb.default_hypercore_use_access_method to false; +set timescaledb.default_hypercore_use_access_method to yes; +set timescaledb.default_hypercore_use_access_method to no; +set timescaledb.default_hypercore_use_access_method to 0; +set timescaledb.default_hypercore_use_access_method to 1; +show timescaledb.default_hypercore_use_access_method; + +-- This should unset the value +reset timescaledb.default_hypercore_use_access_method; +show timescaledb.default_hypercore_use_access_method; + +-- Using GUC should compress using the hyperstore +set timescaledb.default_hypercore_use_access_method to on; +create table test5 (time timestamptz not null, device int, temp float); +select created from create_hypertable('test5', 'time'); +insert into test5 values ('2022-06-01', 1, 1.0), ('2022-08-01', 1, 1.0); + +select ch as chunk from show_chunks('test5') ch limit 1 \gset +alter table test5 set (timescaledb.compress); +select compress_chunk(:'chunk'); +select * from amrels where relparent = 'test5'::regclass;