diff --git a/Makefile b/Makefile index fe907e8d..37073037 100644 --- a/Makefile +++ b/Makefile @@ -195,7 +195,7 @@ set -e -u -x # If you don't want leak checking, use --leak-check=no # # When just doing leak checking and not looking for detailed memory error reports you don't need: -# --track-origins=yes --read-var-info=yes --malloc-fill=8f --free-fill=9f +# --track-origins=yes --read-var-info=yes --malloc-fill=8f --free-fill=9f # SUPP=$(POSTGRES_SRC)/src/tools/valgrind.supp diff --git a/docs/spock_functions/functions/spock_node_create.md b/docs/spock_functions/functions/spock_node_create.md index 1e7c4211..8046c050 100644 --- a/docs/spock_functions/functions/spock_node_create.md +++ b/docs/spock_functions/functions/spock_node_create.md @@ -5,17 +5,26 @@ ### SYNOPSIS `spock.node_create (node_name name, dsn text, location text, country text, info jsonb)` - + ### DESCRIPTION -Create a spock node. +Create a spock node. + Initialize internal state of the spock extension that will be used further in communications with other replication participants to identify the node and connection settings. + It doesn't check correctness or reachability of the dsn at the moment. + Parameters 'location', 'country', and 'info' are optional and is intended for simplifying automatisation infrastructure. -### EXAMPLE +### EXAMPLE `spock.node_create ('n1', 'host=10.1.2.5 user=rocky dbname=demo')` - -### POSITIONAL ARGUMENTS + +### ARGUMENTS node_name - The name of the node. Only one node is allowed per database, and each node in a cluster must have a unique name. To use the Snowflake extension, use the convention n1,n2, etc. Example: n1 + The name of the node. Only one node is allowed per database, and each node in a cluster must have a unique name. Example: n1 dsn The connection string to the node. The user in this string should equal the OS user. This connection string should be reachable from outside and match the one used later in the sub-create command. Example: host=10.1.2.5 port= 5432 user=rocky dbname=demo + location + (optional) Text string identifying the node location as precise as needed. Doesn't affect any internal logic. + country + (optional) Text string dedicated to conveniently store and expose the country code where the spock node is located. Doesn't affect any internal logic. + info + (optional) JSONB field where arbitrary meta information may be stored in structured form. The only optional field that affects the spock behaviour is the 'tiebreaker' integer value that serves as a priority value (less value - more priority) that is used in conflict resolution cases in case commit timestamp is the same for all the concurrent transactions updating the same row. diff --git a/docs/spock_functions/functions/spock_node_drop.md b/docs/spock_functions/functions/spock_node_drop.md index 8c5dff87..77946b02 100644 --- a/docs/spock_functions/functions/spock_node_drop.md +++ b/docs/spock_functions/functions/spock_node_drop.md @@ -5,14 +5,14 @@ ### SYNOPSIS `spock.node_drop (node_name name, ifexists bool)` - + ### DESCRIPTION - Drop a spock node. + Drop a spock node. Beforehand, any subscriptions on remote spock nodes must be deleted by the 'sub_drop' function as well as any subscriptions on the dropping node. -### EXAMPLE +### EXAMPLE `spock.node_drop ('n1')` - + ### POSITIONAL ARGUMENTS node_name The name of the node. Example: n1 diff --git a/docs/spock_functions/functions/spock_sub_create.md b/docs/spock_functions/functions/spock_sub_create.md index 9ee18dd8..e02d1acf 100644 --- a/docs/spock_functions/functions/spock_sub_create.md +++ b/docs/spock_functions/functions/spock_sub_create.md @@ -4,31 +4,30 @@ ### SYNOPSIS -`spock.sub_create (subscription_name name, provider_dsn text, repsets text[], sync_structure boolean, - sync_data boolean, forward_origins text[], apply_delay interval)` - +`spock.sub_create (subscription_name name, provider_dsn text, replication_sets text[], synchronize_structure boolean, synchronize_data boolean, forward_origins text[], apply_delay interval, force_text_transfer boolean, enabled boolean, skip_schema text[])` + ### DESCRIPTION -Creates a subscription from current node to the provider node. The command does not wait for completion before returning to the caller. +Creates a subscription from current node to the provider node. The command does not wait for completion before returning to the caller. Needs preliminary call of the `spock.node_create`. The `subscription_name` is used as `application_name` by the replication connection. This means that it's visible in the `pg_stat_replication` monitoring view. It can also be used in `synchronous_standby_names` when Spock is used as part of a synchronous replication scenario. Use `spock.sub_wait_for_sync(subscription_name)` to wait for the subscription to asynchronously start replicating and complete any needed schema and/or data sync. -### EXAMPLE +### EXAMPLE `spock.sub_create ('sub_n2n1', 'host=10.1.2.5 port=5432 user=rocky dbname=demo')` - + ### ARGUMENTS - subscription_name - The name of the subscription. Each subscription in a cluster must have a unique name. The name is used as application_name by the replication connection. This means that the name is visible in the pg_stat_replication monitoring view. - provider_dsn + subscription_name + The name of the subscription. Each subscription in a cluster must have a unique name. The name is used as application_name by the replication connection. This means that the name is visible in the pg_stat_replication monitoring view. + provider_dsn The connection string to a provider. - repsets + replication_sets An array of existing replication sets to subscribe to; the default is {default,default_insert_only,ddl_sql}. - sync_structure + synchronize_structure Specifies if Spock should synchronize the structure from provider to the subscriber; the default is false. - sync_data + synchronize_data Specifies if Spock should synchronize data from provider to the subscriber, the default is true. forward_origins An array of origin names to forward; currently the only supported values are an empty array (don't forward any changes that didn't originate on provider node, useful for two-way replication between the nodes), or {all} which means replicate all changes no matter what is their origin. The default is {all}. @@ -36,3 +35,7 @@ Use `spock.sub_wait_for_sync(subscription_name)` to wait for the subscription to How much to delay replication; the default is 0 seconds. force_text_transfer Force the provider to replicate all columns using a text representation (which is slower, but may be used to change the type of a replicated column on the subscriber). The default is false. + enabled + If true, it signals replication machinery to activate synchronisation of schema/data from the publisher. If false, the node synchronisation status is set to ready, no synchronization will be made (TODO: refer to a correct use case). The default is true. + skip_schema + Array of schema names that will be skipped during the structure synchronisation. Data from any table, included in these schemas will be filtered at initial data synchronisation. The default is NULL. diff --git a/docs/spock_functions/functions/spock_sub_disable.md b/docs/spock_functions/functions/spock_sub_disable.md index 988ec2af..2814676e 100644 --- a/docs/spock_functions/functions/spock_sub_disable.md +++ b/docs/spock_functions/functions/spock_sub_disable.md @@ -1,21 +1,20 @@ -## NAME +## NAME `spock.sub_disable ()` ### SYNOPSIS `spock.sub_disable (subscription_name name, immediate boolean)` - + ### DESCRIPTION - Disable a subscription by putting it on hold and disconnect from provider. + Disable a subscription by putting it on hold and disconnect from provider. ### EXAMPLE -`spock sub_disable 'sub_n2n1'` - +`spock sub_disable('sub_n2n1')` + ### ARGUMENTS subscription_name The name of the existing subscription. immediate If true, the subscription is stopped immediately, otherwise it will be only stopped at the end of current transaction; the default is false. - diff --git a/docs/spock_functions/functions/spock_sub_drop.md b/docs/spock_functions/functions/spock_sub_drop.md index 31f7740e..db7480e7 100644 --- a/docs/spock_functions/functions/spock_sub_drop.md +++ b/docs/spock_functions/functions/spock_sub_drop.md @@ -5,16 +5,16 @@ ### SYNOPSIS `spock.sub_drop (subscription_name name, ifexists bool)` - + ### DESCRIPTION -Disconnects the subscription and removes it from the catalog. +Disconnects the subscription and removes it from the catalog. ### EXAMPLE `spock.sub_drop ('sub_n2n1')` - -### POSITIONAL ARGUMENTS + +### ARGUMENTS subscription_name The name of the existing subscription. ifexists diff --git a/docs/spock_functions/functions/spock_sub_resync_table.md b/docs/spock_functions/functions/spock_sub_resync_table.md index 509eb79b..b70c3af7 100644 --- a/docs/spock_functions/functions/spock_sub_resync_table.md +++ b/docs/spock_functions/functions/spock_sub_resync_table.md @@ -4,18 +4,20 @@ ### SYNOPSIS -`spock.sub_resync_table (subscription_name name, relation regclass)` - +`spock.sub_resync_table (subscription_name name, relation regclass, truncate boolean)` + ### DESCRIPTION -Resynchronize one existing table. +Resynchronize one existing table. ### EXAMPLE -`spock.sub-resync-table ('sub_n2n1', 'mytable')` - +`spock.sub_resync_table ('sub_n2n1', 'mytable')` + ### POSITIONAL ARGUMENTS subscription_name The name of the existing subscription. relation The name of existing table, optionally schema qualified. + truncate + Truncate table on the subscriber before re-synchronization. In the `false` state any rows, coming from the publisher will be applied other existing state, causing conflicts. The default value is true. diff --git a/docs/spock_functions/functions/spock_sub_show_status.md b/docs/spock_functions/functions/spock_sub_show_status.md index 79207c69..6711a8f5 100644 --- a/docs/spock_functions/functions/spock_sub_show_status.md +++ b/docs/spock_functions/functions/spock_sub_show_status.md @@ -5,15 +5,29 @@ ### SYNOPSIS `spock.sub_show_status (subscription_name name)` - + ### DESCRIPTION -Show the status and basic information of a subscription. +Show the status and basic information of a subscription. ### EXAMPLE `spock.sub_show_status ('sub_n2n1')` - + ### ARGUMENTS subscription_name The optional name of the existing subscription. If no name is provided, the function will show status for all subscriptions on the local node. + +### RETURN + +Returns one record per subscription with the following columns: + +* `subscription_name text`, +* `status text`, +* `provider_node text`, +* `provider_dsn text`, +* `slot_name text`, +* `replication_sets text[]`, +* `forward_origins text[]` + +Column `status` may have one of the following values: `unknown`, `replicating`, `initializing`, `disabled`, or `down`. \ No newline at end of file diff --git a/docs/spock_functions/index.md b/docs/spock_functions/index.md index 5e2fcb37..ed171598 100644 --- a/docs/spock_functions/index.md +++ b/docs/spock_functions/index.md @@ -44,7 +44,6 @@ The following user functions are available via the Spock extension: | spock.spock_version | Returns the Spock version in a major/minor version form: `4.0.10`. | spock.spock_version_num | Returns the Spock version in a single numeric form: `40010`. | spock.get_channel_stats | Returns tuple traffic statistics. -| spock.get_country | Returns the country code if explicitly set; returns `??` if not set. | spock.lag_tracker | Returns a list of slots, with commit_lsn and commit_timestamp for each. | spock.repair_mode | Used to manage the state of replication - If set to `true`, stops replicating statements; when `false`, resumes replication. | spock.replicate_ddl | Replicate a specific statement. diff --git a/sql/spock--6.0.0-devel.sql b/sql/spock--6.0.0-devel.sql index 79d1454b..d37e2528 100644 --- a/sql/spock--6.0.0-devel.sql +++ b/sql/spock--6.0.0-devel.sql @@ -114,34 +114,128 @@ CREATE VIEW spock.progress AS last_updated_ts, updated_by_decode FROM spock.apply_group_progress(); -CREATE FUNCTION spock.node_create(node_name name, dsn text, - location text DEFAULT NULL, country text DEFAULT NULL, - info jsonb DEFAULT NULL) -RETURNS oid CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_create_node'; -CREATE FUNCTION spock.node_drop(node_name name, ifexists boolean DEFAULT false) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_drop_node'; - -CREATE FUNCTION spock.node_add_interface(node_name name, interface_name name, dsn text) -RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_node_add_interface'; -CREATE FUNCTION spock.node_drop_interface(node_name name, interface_name name) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_node_drop_interface'; - -CREATE FUNCTION spock.sub_create(subscription_name name, provider_dsn text, - replication_sets text[] = '{default,default_insert_only,ddl_sql}', synchronize_structure boolean = false, - synchronize_data boolean = false, forward_origins text[] = '{}', apply_delay interval DEFAULT '0', +-- +-- Node Management Functions +-- + +CREATE FUNCTION spock.node_create( + node_name name, + dsn text, + location text DEFAULT NULL, + country text DEFAULT NULL, + info jsonb DEFAULT NULL +) +RETURNS oid CALLED ON NULL INPUT VOLATILE +AS 'MODULE_PATHNAME', 'spock_create_node' +LANGUAGE C; + +CREATE FUNCTION spock.node_drop( + node_name name, + ifexists boolean DEFAULT false +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_drop_node' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION spock.node_info( + OUT node_id oid, + OUT node_name text, + OUT sysid text, + OUT dbname text, + OUT replication_sets text, + OUT location text, + OUT country text, + OUT info jsonb) +RETURNS record +AS 'MODULE_PATHNAME', 'spock_node_info' +LANGUAGE C STABLE STRICT; + +-- +-- SSubscription Management Functions +-- + +CREATE FUNCTION spock.sub_create( + subscription_name name, + provider_dsn text, + replication_sets text[] = '{default,default_insert_only,ddl_sql}', + synchronize_structure boolean = false, + synchronize_data boolean = false, + forward_origins text[] = '{}', + apply_delay interval DEFAULT '0', force_text_transfer boolean = false, - enabled boolean = true, skip_schema text[] = '{}') -RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_create_subscription'; -CREATE FUNCTION spock.sub_drop(subscription_name name, ifexists boolean DEFAULT false) -RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_drop_subscription'; + enabled boolean = true, + skip_schema text[] = '{}' +) +RETURNS oid +AS 'MODULE_PATHNAME', 'spock_create_subscription' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION spock.sub_drop( + subscription_name name, + ifexists boolean DEFAULT false +) +RETURNS oid +AS 'MODULE_PATHNAME', 'spock_drop_subscription' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION spock.sub_disable( + subscription_name name, + immediate boolean DEFAULT false +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_alter_subscription_disable' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION spock.sub_enable( + subscription_name name, + immediate boolean DEFAULT false +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_alter_subscription_enable' +LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION spock.sub_show_status( + subscription_name name DEFAULT NULL, + OUT subscription_name text, + OUT status text, + OUT provider_node text, + OUT provider_dsn text, + OUT slot_name text, + OUT replication_sets text[], + OUT forward_origins text[] +) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'spock_show_subscription_status' +LANGUAGE C STABLE; + +-- +-- Additional interface management routines for complex network configurations +-- + +CREATE FUNCTION spock.node_add_interface( + node_name name, + interface_name name, + dsn text +) +RETURNS oid +AS 'MODULE_PATHNAME', 'spock_alter_node_add_interface' +LANGUAGE C STRICT VOLATILE; -CREATE FUNCTION spock.sub_alter_interface(subscription_name name, interface_name name) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_interface'; +CREATE FUNCTION spock.sub_alter_interface( + subscription_name name, + interface_name name +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_alter_subscription_interface' +LANGUAGE C STRICT VOLATILE; -CREATE FUNCTION spock.sub_disable(subscription_name name, immediate boolean DEFAULT false) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_disable'; -CREATE FUNCTION spock.sub_enable(subscription_name name, immediate boolean DEFAULT false) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_enable'; +CREATE FUNCTION spock.node_drop_interface( + node_name name, + interface_name name +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_alter_node_drop_interface' +LANGUAGE C STRICT VOLATILE; CREATE FUNCTION spock.sub_add_repset(subscription_name name, replication_set name) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_add_replication_set'; @@ -150,12 +244,6 @@ RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_su CREATE FUNCTION spock.sub_alter_skiplsn(subscription_name name, lsn pg_lsn) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_skip_lsn'; -CREATE FUNCTION spock.sub_show_status(subscription_name name DEFAULT NULL, - OUT subscription_name text, OUT status text, OUT provider_node text, - OUT provider_dsn text, OUT slot_name text, OUT replication_sets text[], - OUT forward_origins text[]) -RETURNS SETOF record STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_show_subscription_status'; - CREATE TABLE spock.replication_set ( set_id oid NOT NULL PRIMARY KEY, set_nodeid oid NOT NULL REFERENCES node(node_id) ON UPDATE CASCADE, @@ -264,6 +352,10 @@ CREATE VIEW spock.TABLES AS FROM user_tables t WHERE t.oid NOT IN (SELECT set_reloid FROM set_relations); +-- +-- Replication Set Management Functions +-- + CREATE FUNCTION spock.repset_create(set_name name, replicate_insert boolean = true, replicate_update boolean = true, replicate_delete boolean = true, replicate_truncate boolean = true) @@ -300,9 +392,14 @@ RETURNS int CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spoc CREATE FUNCTION spock.sub_alter_sync(subscription_name name, truncate boolean DEFAULT false) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_synchronize'; -CREATE FUNCTION spock.sub_resync_table(subscription_name name, relation regclass, - truncate boolean DEFAULT true) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_alter_subscription_resynchronize_table'; +CREATE FUNCTION spock.sub_resync_table( + subscription_name name, + relation regclass, + truncate boolean DEFAULT true +) +RETURNS boolean +AS 'MODULE_PATHNAME', 'spock_alter_subscription_resynchronize_table' +LANGUAGE C STRICT VOLATILE; CREATE FUNCTION spock.sync_seq(relation regclass) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'spock_synchronize_sequence'; @@ -338,12 +435,6 @@ CREATE FUNCTION spock.replicate_ddl(command text[], RETURNS SETOF boolean STRICT VOLATILE LANGUAGE sql AS 'SELECT spock.replicate_ddl(cmd, $2, $3, $4) FROM (SELECT unnest(command) cmd)'; -CREATE FUNCTION spock.node_info(OUT node_id oid, OUT node_name text, - OUT sysid text, OUT dbname text, OUT replication_sets text, - OUT location text, OUT country text, OUT info jsonb) -RETURNS record -STABLE STRICT LANGUAGE c AS 'MODULE_PATHNAME', 'spock_node_info'; - CREATE FUNCTION spock.spock_gen_slot_name(name, name, name) RETURNS name IMMUTABLE STRICT LANGUAGE c AS 'MODULE_PATHNAME'; @@ -360,10 +451,6 @@ LANGUAGE c AS 'MODULE_PATHNAME'; CREATE FUNCTION spock_min_proto_version() RETURNS integer LANGUAGE c AS 'MODULE_PATHNAME'; -CREATE FUNCTION spock.get_country() RETURNS text -LANGUAGE sql AS -$$ SELECT current_setting('spock.country') $$; - CREATE FUNCTION spock.wait_slot_confirm_lsn(slotname name, target pg_lsn) RETURNS void LANGUAGE c AS 'spock','spock_wait_slot_confirm_lsn';