From 7aab645184b4f9fc1750f4962f3b4ee5f8fc0009 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Tue, 29 Oct 2024 09:40:42 +0100 Subject: [PATCH] Add GUC for hypercore_use_access_method default Add the GUC `timescaledb.hypercore_use_access_method` for dealing with the default value to use for functions accepting the `hypercore_use_access_method` parameter (`compress_chunk`, `add_compression_policy`, etc.) Value can be "none" (not set, will typically use the "heap" method), "on" (use the hypercore access method) and "off" (do not use the hypercore access method). --- .unreleased/pr_7412 | 1 + src/guc.c | 30 +++++++++++ src/guc.h | 17 ++++++ tsl/src/bgw_policy/compression_api.h | 3 +- tsl/src/compression/api.c | 12 ++++- tsl/src/compression/api.h | 15 ------ tsl/test/expected/hypercore_create.out | 71 ++++++++++++++++++++++++++ tsl/test/sql/hypercore_create.sql | 35 +++++++++++++ 8 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 .unreleased/pr_7412 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 c4c52dd7b8d..c88a329a4e4 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 @@ -138,6 +139,7 @@ bool ts_guc_enable_vectorized_aggregation = true; 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 int ts_guc_default_hypercore_use_access_method = USE_AM_NULL; bool ts_guc_enable_chunk_skipping = false; TSDLLEXPORT bool ts_guc_enable_segmentwise_recompression = true; @@ -412,6 +414,20 @@ ts_guc_default_orderby_fn_oid() return get_orderby_func(ts_guc_default_orderby_fn); } +/* + * Options for the default value of hypercore_use_access_method. + * + * We are following the conventions use by PostgreSQL and use "none" for the + * "unset" value. + */ +static const struct config_enum_entry useam_options[] = { + { "none", USE_AM_NULL, false }, { "on", USE_AM_TRUE, false }, + { "off", USE_AM_FALSE, false }, { "true", USE_AM_TRUE, true }, + { "false", USE_AM_FALSE, true }, { "yes", USE_AM_TRUE, true }, + { "no", USE_AM_FALSE, true }, { "1", USE_AM_TRUE, true }, + { "0", USE_AM_FALSE, true }, { NULL, 0, false } +}; + void _guc_init(void) { @@ -1105,6 +1121,20 @@ _guc_init(void) /* show_hook= */ NULL); #endif + DefineCustomEnumVariable(MAKE_EXTOPTION("default_hypercore_use_access_method"), + gettext_noop( + "Whether to use access method for compression by default."), + gettext_noop( + "Sets the global default for compression technique to use."), + &ts_guc_default_hypercore_use_access_method, + USE_AM_NULL, + /* options= */ useam_options, + /* 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 7c0fb5e0606..249a9d1ba21 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); @@ -101,6 +116,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 int ts_guc_default_hypercore_use_access_method; extern TSDLLEXPORT bool ts_guc_debug_require_batch_sorted_merge; @@ -120,4 +136,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_create.out b/tsl/test/expected/hypercore_create.out index 4e56b1486e4..696e0e6b331 100644 --- a/tsl/test/expected/hypercore_create.out +++ b/tsl/test/expected/hypercore_create.out @@ -921,3 +921,74 @@ 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 +------------------------------------------------- + none +(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 generate an error and not change the value +\set ON_ERROR_STOP 0 +\set VERBOSITY default +set timescaledb.default_hypercore_use_access_method to magic; +ERROR: invalid value for parameter "timescaledb.default_hypercore_use_access_method": "magic" +HINT: Available values: none, on, off. +show timescaledb.default_hypercore_use_access_method; + timescaledb.default_hypercore_use_access_method +------------------------------------------------- + on +(1 row) + +\set VERBOSITY terse +\set ON_ERROR_STOP 1 +-- 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 +------------------------------------------------- + none +(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/sql/hypercore_create.sql b/tsl/test/sql/hypercore_create.sql index 9b0bd02ae41..10fada342b1 100644 --- a/tsl/test/sql/hypercore_create.sql +++ b/tsl/test/sql/hypercore_create.sql @@ -446,3 +446,38 @@ 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 generate an error and not change the value +\set ON_ERROR_STOP 0 +\set VERBOSITY default +set timescaledb.default_hypercore_use_access_method to magic; +show timescaledb.default_hypercore_use_access_method; +\set VERBOSITY terse +\set ON_ERROR_STOP 1 + +-- 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;