From 36c4ec6d53754657fc46b114798f32244f9aadcd Mon Sep 17 00:00:00 2001 From: Marco Slot Date: Fri, 3 Jun 2022 17:49:57 +0200 Subject: [PATCH 1/2] Introduce a citus_finish_citus_upgrade() function --- .../distributed/sql/citus--11.0-1--11.0-2.sql | 1 + src/backend/distributed/sql/citus--8.0-1.sql | 11 ++++- .../sql/downgrades/citus--11.0-2--11.0-1.sql | 1 + .../citus_finish_citus_upgrade/11.0-2.sql | 49 +++++++++++++++++++ .../citus_finish_citus_upgrade/latest.sql | 49 +++++++++++++++++++ src/test/regress/expected/multi_extension.out | 5 +- .../expected/upgrade_list_citus_objects.out | 3 +- 7 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/11.0-2.sql create mode 100644 src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/latest.sql diff --git a/src/backend/distributed/sql/citus--11.0-1--11.0-2.sql b/src/backend/distributed/sql/citus--11.0-1--11.0-2.sql index 53ebae152..78b8b18eb 100644 --- a/src/backend/distributed/sql/citus--11.0-1--11.0-2.sql +++ b/src/backend/distributed/sql/citus--11.0-1--11.0-2.sql @@ -5,3 +5,4 @@ #include "udfs/run_command_on_coordinator/11.0-2.sql" #include "udfs/start_metadata_sync_to_all_nodes/11.0-2.sql" #include "udfs/citus_finalize_upgrade_to_citus11/11.0-2.sql" +#include "udfs/citus_finish_citus_upgrade/11.0-2.sql" diff --git a/src/backend/distributed/sql/citus--8.0-1.sql b/src/backend/distributed/sql/citus--8.0-1.sql index e27c773d7..baac9dd42 100644 --- a/src/backend/distributed/sql/citus--8.0-1.sql +++ b/src/backend/distributed/sql/citus--8.0-1.sql @@ -1461,8 +1461,17 @@ CREATE FUNCTION pg_catalog.citus_server_id() COMMENT ON FUNCTION citus_server_id() IS 'generates a random UUID to be used as server identifier'; +-- Insert the latest extension version into pg_dist_node_metadata +-- for new installations. +-- +-- While users could technically upgrade to an intermediate version +-- everything in Citus fails until it is upgraded to the latest version, +-- so it seems safe to use the latest. INSERT INTO pg_dist_node_metadata - VALUES (jsonb_build_object('server_id', citus_server_id()::text)); +SELECT jsonb_build_object('server_id', citus_server_id()::text, + 'last_upgrade_version', default_version) +FROM pg_available_extensions +WHERE name = 'citus'; -- rebalancer functions CREATE TYPE citus.shard_transfer_mode AS ENUM ( diff --git a/src/backend/distributed/sql/downgrades/citus--11.0-2--11.0-1.sql b/src/backend/distributed/sql/downgrades/citus--11.0-2--11.0-1.sql index 6569f4bbc..7743d5179 100644 --- a/src/backend/distributed/sql/downgrades/citus--11.0-2--11.0-1.sql +++ b/src/backend/distributed/sql/downgrades/citus--11.0-2--11.0-1.sql @@ -16,3 +16,4 @@ DROP FUNCTION pg_catalog.run_command_on_coordinator(text,boolean); DROP FUNCTION pg_catalog.start_metadata_sync_to_all_nodes(); DROP FUNCTION pg_catalog.citus_finalize_upgrade_to_citus11(boolean); +DROP PROCEDURE pg_catalog.citus_finish_citus_upgrade(); diff --git a/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/11.0-2.sql b/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/11.0-2.sql new file mode 100644 index 000000000..b64f1ffa8 --- /dev/null +++ b/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/11.0-2.sql @@ -0,0 +1,49 @@ +CREATE OR REPLACE PROCEDURE pg_catalog.citus_finish_citus_upgrade() + LANGUAGE plpgsql + SET search_path = pg_catalog + AS $cppu$ +DECLARE + current_version_string text; + last_upgrade_version_string text; + last_upgrade_major_version int; + last_upgrade_minor_version int; + last_upgrade_sqlpatch_version int; + performed_upgrade bool := false; +BEGIN + SELECT extversion INTO current_version_string + FROM pg_extension WHERE extname = 'citus'; + + -- assume some arbitrarily old version when no last upgrade version is defined + SELECT coalesce(metadata->>'last_upgrade_version', '8.0-1') INTO last_upgrade_version_string + FROM pg_dist_node_metadata; + + SELECT r[1], r[2], r[3] + FROM regexp_matches(last_upgrade_version_string,'([0-9]+)\.([0-9]+)-([0-9]+)','') r + INTO last_upgrade_major_version, last_upgrade_minor_version, last_upgrade_sqlpatch_version; + + IF last_upgrade_major_version IS NULL OR last_upgrade_minor_version IS NULL OR last_upgrade_sqlpatch_version IS NULL THEN + -- version string is not valid, use an arbitrarily old version number + last_upgrade_major_version := 8; + last_upgrade_minor_version := 0; + last_upgrade_sqlpatch_version := 1; + END IF; + + IF last_upgrade_major_version < 11 THEN + PERFORM citus_finalize_upgrade_to_citus11(); + performed_upgrade := true; + END IF; + + -- add new upgrade steps here + + IF NOT performed_upgrade THEN + RAISE NOTICE 'already at the latest distributed schema version (%)', last_upgrade_version_string; + RETURN; + END IF; + + UPDATE pg_dist_node_metadata + SET metadata = jsonb_set(metadata, array['last_upgrade_version'], to_jsonb(current_version_string)); +END; +$cppu$; + +COMMENT ON PROCEDURE pg_catalog.citus_finish_citus_upgrade() + IS 'after upgrading Citus on all nodes call this function to upgrade the distributed schema'; diff --git a/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/latest.sql b/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/latest.sql new file mode 100644 index 000000000..b64f1ffa8 --- /dev/null +++ b/src/backend/distributed/sql/udfs/citus_finish_citus_upgrade/latest.sql @@ -0,0 +1,49 @@ +CREATE OR REPLACE PROCEDURE pg_catalog.citus_finish_citus_upgrade() + LANGUAGE plpgsql + SET search_path = pg_catalog + AS $cppu$ +DECLARE + current_version_string text; + last_upgrade_version_string text; + last_upgrade_major_version int; + last_upgrade_minor_version int; + last_upgrade_sqlpatch_version int; + performed_upgrade bool := false; +BEGIN + SELECT extversion INTO current_version_string + FROM pg_extension WHERE extname = 'citus'; + + -- assume some arbitrarily old version when no last upgrade version is defined + SELECT coalesce(metadata->>'last_upgrade_version', '8.0-1') INTO last_upgrade_version_string + FROM pg_dist_node_metadata; + + SELECT r[1], r[2], r[3] + FROM regexp_matches(last_upgrade_version_string,'([0-9]+)\.([0-9]+)-([0-9]+)','') r + INTO last_upgrade_major_version, last_upgrade_minor_version, last_upgrade_sqlpatch_version; + + IF last_upgrade_major_version IS NULL OR last_upgrade_minor_version IS NULL OR last_upgrade_sqlpatch_version IS NULL THEN + -- version string is not valid, use an arbitrarily old version number + last_upgrade_major_version := 8; + last_upgrade_minor_version := 0; + last_upgrade_sqlpatch_version := 1; + END IF; + + IF last_upgrade_major_version < 11 THEN + PERFORM citus_finalize_upgrade_to_citus11(); + performed_upgrade := true; + END IF; + + -- add new upgrade steps here + + IF NOT performed_upgrade THEN + RAISE NOTICE 'already at the latest distributed schema version (%)', last_upgrade_version_string; + RETURN; + END IF; + + UPDATE pg_dist_node_metadata + SET metadata = jsonb_set(metadata, array['last_upgrade_version'], to_jsonb(current_version_string)); +END; +$cppu$; + +COMMENT ON PROCEDURE pg_catalog.citus_finish_citus_upgrade() + IS 'after upgrading Citus on all nodes call this function to upgrade the distributed schema'; diff --git a/src/test/regress/expected/multi_extension.out b/src/test/regress/expected/multi_extension.out index b5b99b9f6..233b4895f 100644 --- a/src/test/regress/expected/multi_extension.out +++ b/src/test/regress/expected/multi_extension.out @@ -759,7 +759,7 @@ DROP TABLE columnar_table; ERROR: loaded Citus library version differs from installed extension version CREATE INDEX ON columnar_table (a); ERROR: loaded Citus library version differs from installed extension version -ALTER TABLE columnar_table SET (columnar.compression = pglz); +ALTER TABLE columnar_table SET(columnar.compression = pglz); ERROR: loaded Citus library version differs from installed extension version ALTER TABLE columnar_table RESET (columnar.compression); ERROR: loaded Citus library version differs from installed extension version @@ -1036,10 +1036,11 @@ ALTER EXTENSION citus UPDATE TO '11.0-2'; SELECT * FROM multi_extension.print_extension_changes(); previous_object | current_object --------------------------------------------------------------------- + | function citus_finish_citus_upgrade() | function citus_is_coordinator() boolean | function run_command_on_coordinator(text,boolean) SETOF record | function start_metadata_sync_to_all_nodes() boolean -(3 rows) +(4 rows) -- Test downgrade script (result should be empty) ALTER EXTENSION citus UPDATE TO '11.0-1'; diff --git a/src/test/regress/expected/upgrade_list_citus_objects.out b/src/test/regress/expected/upgrade_list_citus_objects.out index 2b5868018..e361a7040 100644 --- a/src/test/regress/expected/upgrade_list_citus_objects.out +++ b/src/test/regress/expected/upgrade_list_citus_objects.out @@ -60,6 +60,7 @@ ORDER BY 1; function citus_executor_name(integer) function citus_extradata_container(internal) function citus_finalize_upgrade_to_citus11(boolean) + function citus_finish_citus_upgrade() function citus_finish_pg_upgrade() function citus_get_active_worker_nodes() function citus_internal.columnar_ensure_am_depends_catalog() @@ -285,5 +286,5 @@ ORDER BY 1; view columnar.stripe view pg_dist_shard_placement view time_partitions -(269 rows) +(270 rows) From af22a30b48bdb9d66b1cdec8f250dd99619d5648 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Fri, 10 Jun 2022 11:08:47 +0200 Subject: [PATCH 2/2] Use citus_finish_citus_upgrade() in the tests We already have tests relying on citus_finalize_upgrade_to_citus11(). Now, adjust those to rely on citus_finish_citus_upgrade() and always call citus_finish_citus_upgrade(). --- .../after_citus_upgrade_coord_schedule | 1 + .../upgrade_citus_finish_citus_upgrade.out | 23 +++++++++++++++++++ .../expected/upgrade_post_11_after.out | 10 -------- .../upgrade_citus_finish_citus_upgrade.sql | 19 +++++++++++++++ .../regress/sql/upgrade_post_11_after.sql | 4 ---- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 src/test/regress/expected/upgrade_citus_finish_citus_upgrade.out create mode 100644 src/test/regress/sql/upgrade_citus_finish_citus_upgrade.sql diff --git a/src/test/regress/after_citus_upgrade_coord_schedule b/src/test/regress/after_citus_upgrade_coord_schedule index e73837c59..b36151ce6 100644 --- a/src/test/regress/after_citus_upgrade_coord_schedule +++ b/src/test/regress/after_citus_upgrade_coord_schedule @@ -1,5 +1,6 @@ # this schedule is to be run only on coordinators +test: upgrade_citus_finish_citus_upgrade test: upgrade_basic_after test: upgrade_partition_constraints_after test: upgrade_pg_dist_object_test_after diff --git a/src/test/regress/expected/upgrade_citus_finish_citus_upgrade.out b/src/test/regress/expected/upgrade_citus_finish_citus_upgrade.out new file mode 100644 index 000000000..8c46aae43 --- /dev/null +++ b/src/test/regress/expected/upgrade_citus_finish_citus_upgrade.out @@ -0,0 +1,23 @@ +-- Citus upgrades are finished by calling a procedure +-- this is a transactional procedure, so rollback should be fine +BEGIN; + CALL citus_finish_citus_upgrade(); +NOTICE: Preparing all the existing partitioned table indexes +NOTICE: Preparing to sync the metadata to all nodes +ROLLBACK; +-- do the actual job +CALL citus_finish_citus_upgrade(); +NOTICE: Preparing all the existing partitioned table indexes +NOTICE: Preparing to sync the metadata to all nodes +-- show that the upgrade is successfull +SELECT metadata->>'last_upgrade_version' = extversion +FROM pg_dist_node_metadata, pg_extension WHERE extname = 'citus'; + ?column? +--------------------------------------------------------------------- + t +(1 row) + +-- idempotent, should be called multiple times +-- still, do not NOTICE the version as it changes per release +SET client_min_messages TO WARNING; +CALL citus_finish_citus_upgrade(); diff --git a/src/test/regress/expected/upgrade_post_11_after.out b/src/test/regress/expected/upgrade_post_11_after.out index a52c5a2e0..d7d7c46b0 100644 --- a/src/test/regress/expected/upgrade_post_11_after.out +++ b/src/test/regress/expected/upgrade_post_11_after.out @@ -1,14 +1,4 @@ SET search_path = post_11_upgrade; --- make sure that we always (re)sync the metadata -UPDATE pg_dist_node_metadata SET metadata=jsonb_set(metadata, '{partitioned_citus_table_exists_pre_11}', to_jsonb('true'::bool), true); -SELECT citus_finalize_upgrade_to_citus11(enforce_version_check:=false); -NOTICE: Preparing all the existing partitioned table indexes -NOTICE: Preparing to sync the metadata to all nodes - citus_finalize_upgrade_to_citus11 ---------------------------------------------------------------------- - t -(1 row) - -- tables, views and their dependencies become objects with Citus 11+ SELECT pg_identify_object_as_address(classid, objid, objsubid) FROM pg_catalog.pg_dist_object WHERE objid IN ('post_11_upgrade'::regnamespace, 'post_11_upgrade.part_table'::regclass, 'post_11_upgrade.sensors'::regclass, 'post_11_upgrade.func_in_transaction_def'::regproc, 'post_11_upgrade.partial_index_test_config'::regconfig, 'post_11_upgrade.my_type'::regtype, 'post_11_upgrade.employees'::regclass, 'post_11_upgrade.view_for_upgrade_test'::regclass, 'post_11_upgrade.my_type_for_view'::regtype, 'post_11_upgrade.view_for_upgrade_test_my_type'::regclass, 'post_11_upgrade.non_dist_table_for_view'::regclass, 'post_11_upgrade.non_dist_upgrade_test_view'::regclass, 'post_11_upgrade.non_dist_upgrade_test_view_local_join'::regclass, 'post_11_upgrade.non_dist_upgrade_multiple_dist_view'::regclass, 'post_11_upgrade.non_dist_upgrade_ref_view'::regclass, 'post_11_upgrade.non_dist_upgrade_ref_view_2'::regclass, 'post_11_upgrade.reporting_line'::regclass, 'post_11_upgrade.v_test_1'::regclass, 'post_11_upgrade.v_test_2'::regclass, 'post_11_upgrade.owned_by_extension_table'::regclass, 'post_11_upgrade.materialized_view'::regclass, 'post_11_upgrade.owned_by_extension_view'::regclass, 'post_11_upgrade.local_type'::regtype, 'post_11_upgrade.non_dist_dist_table_for_view'::regclass, 'post_11_upgrade.depends_on_nothing_1'::regclass, 'post_11_upgrade.depends_on_nothing_2'::regclass, 'post_11_upgrade.depends_on_pg'::regclass, 'post_11_upgrade.depends_on_citus'::regclass, 'post_11_upgrade.depends_on_seq'::regclass, 'post_11_upgrade.depends_on_seq_and_no_support'::regclass) ORDER BY 1; pg_identify_object_as_address diff --git a/src/test/regress/sql/upgrade_citus_finish_citus_upgrade.sql b/src/test/regress/sql/upgrade_citus_finish_citus_upgrade.sql new file mode 100644 index 000000000..bc2c40b0c --- /dev/null +++ b/src/test/regress/sql/upgrade_citus_finish_citus_upgrade.sql @@ -0,0 +1,19 @@ +-- Citus upgrades are finished by calling a procedure + +-- this is a transactional procedure, so rollback should be fine +BEGIN; + CALL citus_finish_citus_upgrade(); +ROLLBACK; + +-- do the actual job +CALL citus_finish_citus_upgrade(); + +-- show that the upgrade is successfull + +SELECT metadata->>'last_upgrade_version' = extversion +FROM pg_dist_node_metadata, pg_extension WHERE extname = 'citus'; + +-- idempotent, should be called multiple times +-- still, do not NOTICE the version as it changes per release +SET client_min_messages TO WARNING; +CALL citus_finish_citus_upgrade(); diff --git a/src/test/regress/sql/upgrade_post_11_after.sql b/src/test/regress/sql/upgrade_post_11_after.sql index 71c15614f..e38491593 100644 --- a/src/test/regress/sql/upgrade_post_11_after.sql +++ b/src/test/regress/sql/upgrade_post_11_after.sql @@ -1,9 +1,5 @@ SET search_path = post_11_upgrade; --- make sure that we always (re)sync the metadata -UPDATE pg_dist_node_metadata SET metadata=jsonb_set(metadata, '{partitioned_citus_table_exists_pre_11}', to_jsonb('true'::bool), true); -SELECT citus_finalize_upgrade_to_citus11(enforce_version_check:=false); - -- tables, views and their dependencies become objects with Citus 11+ SELECT pg_identify_object_as_address(classid, objid, objsubid) FROM pg_catalog.pg_dist_object WHERE objid IN ('post_11_upgrade'::regnamespace, 'post_11_upgrade.part_table'::regclass, 'post_11_upgrade.sensors'::regclass, 'post_11_upgrade.func_in_transaction_def'::regproc, 'post_11_upgrade.partial_index_test_config'::regconfig, 'post_11_upgrade.my_type'::regtype, 'post_11_upgrade.employees'::regclass, 'post_11_upgrade.view_for_upgrade_test'::regclass, 'post_11_upgrade.my_type_for_view'::regtype, 'post_11_upgrade.view_for_upgrade_test_my_type'::regclass, 'post_11_upgrade.non_dist_table_for_view'::regclass, 'post_11_upgrade.non_dist_upgrade_test_view'::regclass, 'post_11_upgrade.non_dist_upgrade_test_view_local_join'::regclass, 'post_11_upgrade.non_dist_upgrade_multiple_dist_view'::regclass, 'post_11_upgrade.non_dist_upgrade_ref_view'::regclass, 'post_11_upgrade.non_dist_upgrade_ref_view_2'::regclass, 'post_11_upgrade.reporting_line'::regclass, 'post_11_upgrade.v_test_1'::regclass, 'post_11_upgrade.v_test_2'::regclass, 'post_11_upgrade.owned_by_extension_table'::regclass, 'post_11_upgrade.materialized_view'::regclass, 'post_11_upgrade.owned_by_extension_view'::regclass, 'post_11_upgrade.local_type'::regtype, 'post_11_upgrade.non_dist_dist_table_for_view'::regclass, 'post_11_upgrade.depends_on_nothing_1'::regclass, 'post_11_upgrade.depends_on_nothing_2'::regclass, 'post_11_upgrade.depends_on_pg'::regclass, 'post_11_upgrade.depends_on_citus'::regclass, 'post_11_upgrade.depends_on_seq'::regclass, 'post_11_upgrade.depends_on_seq_and_no_support'::regclass) ORDER BY 1;