Skip to content

Commit 582cb36

Browse files
mason-sharpclaude
andcommitted
Fix incorrect subscription name in Phase 9 of ZODAN add_node (SPOC-503)
create_sub_on_new_node_to_src_node generated sub_{subscriber}_{provider} instead of the expected sub_{provider}_{subscriber} convention, causing remove-node to fail when looking up subscriptions by their expected name. Introduce spock.gen_sub_name(provider_node, subscriber_node) helper and replace all inline 'sub_' || concatenations to prevent future mismatches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c85bc2f commit 582cb36

1 file changed

Lines changed: 29 additions & 13 deletions

File tree

samples/Z0DAN/zodan.sql

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@
2828

2929
-- ============================================================================
3030

31+
-- ============================================================================
32+
-- Function: gen_sub_name
33+
-- Purpose : Generate a subscription name following the sub_{provider}_{subscriber}
34+
-- convention (i.e. sub_{remote}_{local}).
35+
-- Arguments:
36+
-- provider_node - The node supplying data (remote/provider).
37+
-- subscriber_node - The node receiving data (local/subscriber).
38+
-- Returns : text, e.g. 'sub_n1_n2' where n1 is the provider and n2 is the subscriber.
39+
-- ============================================================================
40+
CREATE OR REPLACE FUNCTION spock.gen_sub_name(
41+
provider_node text,
42+
subscriber_node text
43+
) RETURNS text LANGUAGE sql IMMUTABLE AS $$
44+
SELECT 'sub_' || provider_node || '_' || subscriber_node;
45+
$$;
46+
3147
-- ============================================================================
3248
-- Procedure: check_spock_version_compatibility
3349
-- Purpose: Verify all nodes have the same Spock version before adding a node
@@ -1217,7 +1233,7 @@ BEGIN
12171233

12181234
slot_name := spock.spock_gen_slot_name(
12191235
dbname, rec.node_name,
1220-
'sub_' || rec.node_name || '_' || new_node_name);
1236+
spock.gen_sub_name(rec.node_name, new_node_name));
12211237

12221238
CALL spock.create_replication_slot(
12231239
rec.dsn,
@@ -1312,7 +1328,7 @@ BEGIN
13121328

13131329
slot_name := spock.spock_gen_slot_name(
13141330
dbname, rec.node_name,
1315-
'sub_' || rec.node_name || '_' || new_node_name);
1331+
spock.gen_sub_name(rec.node_name, new_node_name));
13161332

13171333
remotesql := format('SELECT slot_name, lsn FROM pg_create_logical_replication_slot(%L, ''spock_output'');', slot_name);
13181334
IF verb THEN
@@ -1415,7 +1431,7 @@ BEGIN
14151431

14161432
-- Create disabled subscription on new node from "other" node
14171433
BEGIN
1418-
sub_name := 'sub_' || rec.node_name || '_' || new_node_name;
1434+
sub_name := spock.gen_sub_name(rec.node_name, new_node_name);
14191435
-- Drop stale replication origin from a previous add_node cycle
14201436
-- so create_sub starts fresh at 0/0 (avoids stale-LSN data loss).
14211437
BEGIN
@@ -1488,7 +1504,7 @@ BEGIN
14881504
IF (SELECT count(*) FROM temp_spock_nodes WHERE node_name != src_node_name AND node_name != new_node_name) = 0 THEN
14891505
-- 2-node scenario: enable the disabled subscription from source to new node
14901506

1491-
sub_name := 'sub_' || src_node_name || '_' || new_node_name;
1507+
sub_name := spock.gen_sub_name(src_node_name, new_node_name);
14921508

14931509
BEGIN
14941510
CALL spock.enable_sub( new_node_dsn, sub_name, verb, true);
@@ -1548,7 +1564,7 @@ BEGIN
15481564
-- Verify subscription is replicating after enabling (2-node scenario)
15491565
CALL spock.verify_subscription_replicating(
15501566
new_node_dsn,
1551-
'sub_' || src_node_name || '_' || new_node_name,
1567+
spock.gen_sub_name(src_node_name, new_node_name),
15521568
verb,
15531569
180
15541570
);
@@ -1575,7 +1591,7 @@ BEGIN
15751591
CONTINUE; -- Skip new node to avoid self-subscription
15761592
END IF;
15771593

1578-
sub_name := 'sub_'|| rec.node_name || '_' || new_node_name;
1594+
sub_name := spock.gen_sub_name(rec.node_name, new_node_name);
15791595

15801596
CALL spock.enable_sub(new_node_dsn, sub_name, verb, true);
15811597

@@ -1619,7 +1635,7 @@ BEGIN
16191635
-- Verify subscription is replicating after enabling
16201636
CALL spock.verify_subscription_replicating(
16211637
new_node_dsn,
1622-
'sub_'|| rec.node_name || '_' || new_node_name,
1638+
spock.gen_sub_name(rec.node_name, new_node_name),
16231639
verb,
16241640
180
16251641
);
@@ -1661,7 +1677,7 @@ BEGIN
16611677

16621678
-- For each existing node (excluding new node), create subscription TO the new node
16631679
FOR rec IN SELECT * FROM temp_spock_nodes WHERE node_name != new_node_name LOOP
1664-
sub_name := 'sub_' || rec.node_name || '_' || new_node_name;
1680+
sub_name := spock.gen_sub_name(new_node_name, rec.node_name);
16651681
BEGIN
16661682
CALL spock.create_sub(
16671683
rec.dsn, -- Create on existing node
@@ -1704,7 +1720,7 @@ CREATE OR REPLACE PROCEDURE spock.create_new_to_source_subscription(
17041720
verb boolean
17051721
) LANGUAGE plpgsql AS $$
17061722
DECLARE
1707-
sub_name text := 'sub_' || new_node_name || '_' || src_node_name;
1723+
sub_name text := spock.gen_sub_name(new_node_name, src_node_name);
17081724
BEGIN
17091725
RAISE NOTICE 'Phase 10: Creating new to source node subscription';
17101726

@@ -1738,7 +1754,7 @@ CREATE OR REPLACE PROCEDURE spock.create_source_to_new_subscription(
17381754
verb boolean -- Verbose flag
17391755
) LANGUAGE plpgsql AS $$
17401756
DECLARE
1741-
sub_name text := 'sub_' || src_node_name || '_' || new_node_name;
1757+
sub_name text := spock.gen_sub_name(src_node_name, new_node_name);
17421758
BEGIN
17431759
RAISE NOTICE 'Phase 4: Creating source to new node subscription';
17441760

@@ -1857,7 +1873,7 @@ BEGIN
18571873
RAISE NOTICE 'Phase 7: Checking commit timestamp and advancing replication slot';
18581874

18591875
-- Wait for src->new COPY to complete so resume_lsn is written to spock.progress.
1860-
v_sub_name := ('sub_' || src_node_name || '_' || new_node_name)::name;
1876+
v_sub_name := spock.gen_sub_name(src_node_name, new_node_name)::name;
18611877
RAISE NOTICE ' - Waiting for subscription % to reach READY...', v_sub_name;
18621878
BEGIN
18631879
-- Avoid rare hangs in C-level sub_wait_for_sync by using a bounded SQL loop.
@@ -1918,7 +1934,7 @@ BEGIN
19181934
-- Generate slot name: spk_<dbname>_<src>_sub_<src>_<new>
19191935
src_slot_name := spock.spock_gen_slot_name(
19201936
src_dbname, src_node_name,
1921-
'sub_' || src_node_name || '_' || new_node_name);
1937+
spock.gen_sub_name(src_node_name, new_node_name));
19221938

19231939
RAISE NOTICE ' Looking for slot % on source node', src_slot_name;
19241940

@@ -2017,7 +2033,7 @@ BEGIN
20172033
END IF;
20182034
IF dbname IS NULL THEN dbname := 'pgedge'; END IF;
20192035

2020-
slot_name := spock.spock_gen_slot_name(dbname, rec.node_name, 'sub_' || rec.node_name || '_' || new_node_name);
2036+
slot_name := spock.spock_gen_slot_name(dbname, rec.node_name, spock.gen_sub_name(rec.node_name, new_node_name));
20212037

20222038
-- First check if slot exists and get current LSN
20232039
remotesql := format('SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = %L', slot_name);

0 commit comments

Comments
 (0)