Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 84742fe

Browse files
committed
Support 2PC: create one FDW server per node
1 parent e7b7037 commit 84742fe

File tree

1 file changed

+59
-48
lines changed

1 file changed

+59
-48
lines changed

shard.sql

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -421,20 +421,20 @@ BEGIN
421421
END $$ LANGUAGE plpgsql STRICT;
422422

423423
-- Drop all foreign server's options. Yes, I don't know simpler ways.
424-
CREATE FUNCTION reset_foreign_server_opts(sname name) RETURNS void AS $$
424+
CREATE FUNCTION reset_foreign_server_opts(server_name name) RETURNS void AS $$
425425
DECLARE
426426
opts text[];
427427
opt text;
428428
opt_key text;
429429
BEGIN
430-
ASSERT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = sname);
430+
ASSERT EXISTS (SELECT 1 from pg_foreign_server WHERE srvname=server_name);
431431
EXECUTE format($q$SELECT coalesce(srvoptions, '{}'::text[]) FROM
432432
pg_foreign_server WHERE srvname = %L$q$,
433-
sname) INTO opts;
434-
FOREACH opt IN ARRAY opts LOOP
435-
opt_key := regexp_replace(substring(opt from '^.*?='), '=$', '');
436-
EXECUTE format('ALTER SERVER %I OPTIONS (DROP %s);', sname, opt_key);
437-
END LOOP;
433+
server_name) INTO opts;
434+
FOREACH opt IN ARRAY opts LOOP
435+
opt_key := regexp_replace(substring(opt from '^.*?='), '=$', '');
436+
EXECUTE format('ALTER SERVER %I OPTIONS (DROP %s);', server_name, opt_key);
437+
END LOOP;
438438
END $$ LANGUAGE plpgsql STRICT;
439439
-- Same for resetting user mapping opts
440440
CREATE or replace FUNCTION reset_um_opts(srvname name, umuser regrole)
@@ -449,19 +449,53 @@ BEGIN
449449
ON fs.oid = ums.umserver WHERE fs.srvname = %L AND
450450
ums.umuser = umuser$q$, srvname)
451451
INTO opts;
452-
453-
FOREACH opt IN ARRAY opts LOOP
454-
opt_key := regexp_replace(substring(opt from '^.*?='), '=$', '');
455-
EXECUTE format('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (DROP %s);',
452+
IF opts IS NOT NULL THEN
453+
FOREACH opt IN ARRAY opts LOOP
454+
opt_key := regexp_replace(substring(opt from '^.*?='), '=$', '');
455+
EXECUTE format('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (DROP %s);',
456456
umuser::name, srvname, opt_key);
457-
END LOOP;
457+
END LOOP;
458+
END IF;
459+
END $$ LANGUAGE plpgsql STRICT;
460+
461+
CREATE FUNCTION create_foreign_server(node_id integer) RETURNS void AS $$
462+
DECLARE
463+
connstring text;
464+
server_opts text;
465+
um_opts text;
466+
server_name text;
467+
BEGIN
468+
SELECT nodes.connstring FROM shardman.nodes WHERE id = node_id
469+
INTO connstring;
470+
SELECT * FROM shardman.conninfo_to_postgres_fdw_opts(connstring)
471+
INTO server_opts, um_opts;
472+
server_name := 'node_'||node_id;
473+
IF NOT EXISTS (SELECT 1 from pg_foreign_server WHERE srvname=server_name)
474+
THEN
475+
RAISE DEBUG 'Create foreign server % for with options %', server_name, server_opts;
476+
EXECUTE format('CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw %s;',
477+
server_name, server_opts);
478+
-- TODO: support not only CURRENT_USER
479+
EXECUTE format('CREATE USER MAPPING FOR CURRENT_USER SERVER %I %s;',
480+
server_name, um_opts);
481+
ELSE
482+
RAISE DEBUG 'Use existed foreign server % with options %', server_name, server_opts;
483+
PERFORM shardman.reset_foreign_server_opts(server_name);
484+
PERFORM shardman.reset_um_opts(server_name, current_user::regrole);
485+
486+
IF server_opts != '' THEN
487+
EXECUTE format('ALTER SERVER %I %s', server_name, server_opts);
488+
END IF;
489+
IF um_opts != '' THEN
490+
EXECUTE format('ALTER USER MAPPING FOR CURRENT_USER SERVER %I %s',
491+
server_name, um_opts);
492+
END IF;
493+
END IF;
458494
END $$ LANGUAGE plpgsql STRICT;
459495

460496
-- Update foreign server and user mapping params on current node according to
461497
-- partition part, so this is expected to be called on server/um params
462-
-- change. We use dedicated server for each partition because we plan to use
463-
-- multiple hosts/ports in connstrings for transient fallback to replica if
464-
-- server with main partition fails. FDW server, user mapping, foreign table and
498+
-- change. FDW server, user mapping, foreign table and
465499
-- (obviously) parent partition must exist when called if they need to be
466500
-- updated; however, it is ok to call this func on nodes which don't need fdw
467501
-- setup for this part because they hold primary partition.
@@ -472,6 +506,8 @@ DECLARE
472506
um_opts text;
473507
me int := shardman.my_id();
474508
my_part shardman.partitions;
509+
server_oid oid;
510+
foreign_table_oid oid;
475511
BEGIN
476512
RAISE DEBUG '[SHMN] update_fdw_server called for part %, owner %',
477513
part.part_name, part.owner;
@@ -487,24 +523,11 @@ BEGIN
487523
END IF;
488524
END IF;
489525

490-
SELECT nodes.connstring FROM shardman.nodes WHERE id = part.owner
491-
INTO connstring;
492-
SELECT * FROM shardman.conninfo_to_postgres_fdw_opts(connstring)
493-
INTO server_opts, um_opts;
494-
495-
-- ALTER FOREIGN TABLE doesn't support changing server, ALTER SERVER doesn't
496-
-- support dropping all params, and I don't want to recreate foreign table
497-
-- each time server params change, so resorting to these hacks.
498-
PERFORM shardman.reset_foreign_server_opts(part.part_name);
499-
PERFORM shardman.reset_um_opts(part.part_name, current_user::regrole);
526+
PERFORM shardman.create_foreign_server(part.owner);
500527

501-
IF server_opts != '' THEN
502-
EXECUTE format('ALTER SERVER %I %s', part.part_name, server_opts);
503-
END IF;
504-
IF um_opts != '' THEN
505-
EXECUTE format('ALTER USER MAPPING FOR CURRENT_USER SERVER %I %s',
506-
part.part_name, um_opts);
507-
END IF;
528+
SELECT oid FROM pg_foreign_server WHERE srvname='node_'||part.owner into server_oid;
529+
SELECT oid FROM pg_class WHERE relname=part.part_name||'_fdw' into foreign_table_oid;
530+
UPDATE pg_foreign_table SET ftserver = server_oid WHERE ftrelid = foreign_table_oid;
508531
END $$ LANGUAGE plpgsql STRICT;
509532

510533
-- Replace existing hash partition with foreign, assuming 'partition' shows
@@ -514,23 +537,11 @@ CREATE FUNCTION replace_usual_part_with_foreign(part partitions)
514537
DECLARE
515538
connstring text;
516539
fdw_part_name text;
517-
server_opts text;
518-
um_opts text;
540+
server_name text;
519541
BEGIN
520-
EXECUTE format('DROP SERVER IF EXISTS %I CASCADE;', part.part_name);
521-
522-
SELECT nodes.connstring FROM shardman.nodes WHERE id = part.owner
523-
INTO connstring;
524-
SELECT * FROM shardman.conninfo_to_postgres_fdw_opts(connstring)
525-
INTO server_opts, um_opts;
542+
server_name := 'node_'||part.owner;
543+
PERFORM shardman.create_foreign_server(part.owner);
526544

527-
EXECUTE format('CREATE SERVER %I FOREIGN DATA WRAPPER
528-
postgres_fdw %s;', part.part_name, server_opts);
529-
EXECUTE format('DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER %I;',
530-
part.part_name);
531-
-- TODO: support not only CURRENT_USER
532-
EXECUTE format('CREATE USER MAPPING FOR CURRENT_USER SERVER %I
533-
%s;', part.part_name, um_opts);
534545
SELECT shardman.get_fdw_part_name(part.part_name) INTO fdw_part_name;
535546
EXECUTE format('DROP FOREIGN TABLE IF EXISTS %I;', fdw_part_name);
536547

@@ -552,7 +563,7 @@ BEGIN
552563
(SELECT
553564
shardman.reconstruct_table_attrs(
554565
format('%I', part.relation))),
555-
part.part_name,
566+
server_name,
556567
part.part_name);
557568
-- replace local partition with foreign table
558569
EXECUTE format('SELECT replace_hash_partition(%L, %L)',

0 commit comments

Comments
 (0)