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

Commit e76820d

Browse files
committed
Synchronous replication, better Makefile, fixes.
* Synchronous replication works. * For that, add 'set synchronous_commit to local' to every stmt in broadcast if it is not ALTER SYSTEM (the latter is forbidden in multi-stmt queries). * Now subscription names are node_$pubnodeid_$subnode_id to avoid application_name collisions. * PGXS is used by default. * Removed 'continue' in cleanup of broadcast. * Identation fixes.
1 parent f7948c3 commit e76820d

File tree

7 files changed

+156
-141
lines changed

7 files changed

+156
-141
lines changed

Makefile

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
1-
# contrib/pg_shardman/Makefile
2-
31
# the extension name
42
EXTENSION = pg_shardman
3+
EXTVERSION = 1.0
54
# This file will be executed by CREATE EXTENSION, so let pgxs install it.
6-
DATA = pg_shardman--1.0.sql
5+
DATA = $(EXTENSION)--$(EXTVERSION).sql
76

87
MODULE_big = pg_shardman
98
OBJS = pg_shardman.o
109
PGFILEDESC = "pg_shardman - sharding for Postgres"
1110

11+
ifdef USE_SOURCETREE # assume the extension is in contrib/ dir of pg distribution
1212
PG_CPPFLAGS = -I$(libpq_srcdir)
1313
SHLIB_LINK = $(libpq)
14-
15-
ifdef USE_PGXS
16-
PG_CONFIG = pg_config
17-
PGXS := $(shell $(PG_CONFIG) --pgxs)
18-
include $(PGXS)
19-
else
2014
SHLIB_PREREQS = submake-libpq
2115
subdir = contrib/pg_shardman
2216
top_builddir = ../..
2317
include $(top_builddir)/src/Makefile.global
2418
include $(top_srcdir)/contrib/contrib-global.mk
19+
else # use pgxs
20+
# You can specify path to pg_config in PG_CONFIG var
21+
ifndef PG_CONFIG
22+
PG_CONFIG := pg_config
23+
endif
24+
PG_CONFIG = pg_config
25+
26+
INCLUDEDIR := $(shell $(PG_CONFIG) --includedir)
27+
PG_CPPFLAGS += -I$(INCLUDEDIR) # add server's include directory for libpq-fe.h
28+
SHLIB_LINK += -lpq # add libpq
29+
30+
PGXS := $(shell $(PG_CONFIG) --pgxs)
31+
include $(PGXS)
2532
endif

bin/cancel_cmd.sh

Lines changed: 0 additions & 3 deletions
This file was deleted.

bin/shardman_init.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ make install
1616
> $logfile
1717

1818
stop_nodes
19+
pkill -9 postgres || true
1920
for datadir in $lord_datadir "${worker_datadirs[@]}"; do
2021
rm -rf "$datadir"
2122
mkdir -p "$datadir"

pg_shardman--1.0.sql

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ DECLARE
6161
um_opts text;
6262
new_server_opts text;
6363
new_um_opts text;
64-
sync_standbys text;
64+
sync_standbys text[];
6565
shardlord_conn_string text;
6666
create_table text;
6767
create_tables text = '';
@@ -71,20 +71,17 @@ DECLARE
7171
fdw_part_name text;
7272
table_attrs text;
7373
srv_name text;
74+
sync_standbyss text = 'haha';
7475
BEGIN
7576
-- Insert new node in nodes table
7677
INSERT INTO shardman.nodes (connection_string,replication_group) VALUES (conn_string, repl_group) RETURNING id INTO new_node_id;
7778

78-
-- Construct list of synchronous standbyes (subscriptions have name node_$ID)
79-
SELECT string_agg('node_'||id, ',') INTO sync_standbys from shardman.nodes;
80-
-- Construct foreign server options from connection string of new node
81-
SELECT * FROM shardman.conninfo_to_postgres_fdw_opts(conn_string) INTO new_server_opts, new_um_opts;
82-
8379
-- Adjust replication channels within replication group.
8480
-- We need all-to-all replication channels between all group members.
85-
FOR node IN SELECT * FROM shardman.nodes WHERE replication_group=repl_group AND id<>new_node_id
81+
FOR node IN SELECT * FROM shardman.nodes WHERE replication_group = repl_group AND id <> new_node_id
8682
LOOP
87-
-- Add to new node publications for all existed nodes and add publication for new node to all existed nodes
83+
-- Add to new node publications for all existing nodes and add
84+
-- publication for new node to all existing nodes
8885
pubs := format('%s%s:CREATE PUBLICATION node_%s;
8986
%s:CREATE PUBLICATION node_%s;
9087
%s:SELECT pg_create_logical_replication_slot(''node_%s'', ''pgoutput'');
@@ -93,17 +90,14 @@ BEGIN
9390
new_node_id, node.id,
9491
node.id, new_node_id,
9592
new_node_id, node.id);
96-
-- Add to new node subscriptions to existed nodes and add subscription to new node to all existed nodes
97-
subs := format('%s%s:CREATE SUBSCRIPTION node_%s CONNECTION %L PUBLICATION node_%s with (create_slot=false, slot_name=''node_%s'', synchronous_commit=local);
98-
%s:CREATE SUBSCRIPTION node_%s CONNECTION %L PUBLICATION node_%s with (create_slot=false, slot_name=''node_%s'', synchronous_commit=local);',
99-
subs, node.id, new_node_id, conn_string, node.id, node.id,
100-
new_node_id, node.id, node.connection_string, new_node_id, new_node_id);
101-
102-
-- Adjust synchronous standby list at all nodes
103-
sync := format('%s%s:ALTER SYSTEM SET synchronous_standby_names to %L;',
104-
sync, node.id, sync_standbys);
105-
conf := format('%s%s:SELECT pg_reload_conf();',
106-
conf, node.id);
93+
-- Add to new node subscriptions to existing nodes and add subscription
94+
-- to new node to all existing nodes
95+
-- sub name is node_pubnodeid_subnodeid to avoid application_name collision
96+
subs := format('%s%s:CREATE SUBSCRIPTION node_%s_%s CONNECTION %L PUBLICATION node_%s with (create_slot=false, slot_name=''node_%s'', synchronous_commit=local);
97+
%s:CREATE SUBSCRIPTION node_%s_%s CONNECTION %L PUBLICATION node_%s with (create_slot=false, slot_name=''node_%s'', synchronous_commit=local);',
98+
subs,
99+
node.id, new_node_id, node.id, conn_string, node.id, node.id,
100+
new_node_id, node.id, new_node_id, node.connection_string, new_node_id, new_node_id);
107101
END LOOP;
108102

109103
-- Broadcast create publication commands
@@ -112,19 +106,26 @@ BEGIN
112106
PERFORM shardman.broadcast(subs);
113107

114108
-- In case of synchronous replication broadcast update synchronous standby list commands
115-
IF shardman.synchronous_replication()
109+
IF shardman.synchronous_replication() AND
110+
(SELECT COUNT(*) FROM shardman.nodes WHERE replication_group = repl_group) > 1
116111
THEN
117-
-- Adjust synchronous standby list at new nodes
118-
sync := format('%s%s:ALTER SYSTEM SET synchronous_standby_names to %L;',
119-
sync, new_node_id, sync_stanbys);
120-
-- Reload configuration at new node
121-
conf := format('%s%s:SELECT pg_reload_conf();',
122-
conf, new_node_id);
112+
-- Take all nodes in replicationg group excluding myself
113+
FOR node IN SELECT * FROM shardman.nodes WHERE replication_group = repl_group LOOP
114+
sync_standbys :=
115+
ARRAY(SELECT string_agg(format('node_%s_%s', node.id, id), ',') FROM shardman.nodes
116+
WHERE replication_group = repl_group AND id <> node.id);
117+
sync := format('%s%s:ALTER SYSTEM SET synchronous_standby_names to ''FIRST %s (%s)'';',
118+
sync, node.id, array_length(sync_standbys, 1),
119+
array_to_string(sync_standbys, ','));
120+
conf := format('%s%s:SELECT pg_reload_conf();', conf, node.id);
121+
END LOOP;
123122
PERFORM shardman.broadcast(sync);
124123
PERFORM shardman.broadcast(conf);
125124
END IF;
126125

127126
-- Add foreign servers for connection to the new node and backward
127+
-- Construct foreign server options from connection string of new node
128+
SELECT * FROM shardman.conninfo_to_postgres_fdw_opts(conn_string) INTO new_server_opts, new_um_opts;
128129
FOR node IN SELECT * FROM shardman.nodes WHERE id<>new_node_id
129130
LOOP
130131
-- Construct foreign server options from connection string of this node
@@ -181,8 +182,9 @@ END
181182
$$ LANGUAGE plpgsql;
182183

183184

184-
-- Remove node: try to choose alternative from one of replicas of this nodes, exclude node from replication channels and remove foreign servers.
185-
-- To remove node with existed partitions use force=true parameter
185+
-- Remove node: try to choose alternative from one of replicas of this nodes,
186+
-- exclude node from replication channels and remove foreign servers.
187+
-- To remove node with existing partitions use force=true parameter.
186188
CREATE FUNCTION rm_node(rm_node_id int, force bool = false) RETURNS void AS $$
187189
DECLARE
188190
node shardman.nodes;
@@ -198,14 +200,14 @@ DECLARE
198200
BEGIN
199201
-- If it is not forced remove, check if there are no partitions at this node
200202
IF NOT force THEN
201-
IF EXISTS (SELECT * FROM shardman.partitions WHERE node=rm_node_id)
203+
IF EXISTS (SELECT * FROM shardman.partitions parts WHERE parts.node = rm_node_id)
202204
THEN
203205
RAISE EXCEPTION 'Use force=true to remove non-empty node';
204206
END IF;
205207
END IF;
206208

207209
-- Construct new synchronous standby list
208-
SELECT string_agg('node_'||id, ',') INTO sync_standbys from shardman.nodes WHERE id<>rm_node_id;
210+
SELECT string_agg('node_' || id, ',') INTO sync_standbys from shardman.nodes WHERE id<>rm_node_id;
209211

210212
-- Remove all subscriptions and publications of this node
211213
FOR node IN SELECT * FROM shardman.nodes WHERE replication_group=repl_group AND id<>rm_node_id
@@ -333,7 +335,7 @@ DECLARE
333335
i int;
334336
n_nodes int;
335337
BEGIN
336-
IF EXISTS(SELECT relation from shardman.partitions where relation = rel_name)
338+
IF EXISTS(SELECT relation FROM shardman.partitions WHERE relation = rel_name)
337339
THEN
338340
RAISE EXCEPTION 'Table % is already sharded', rel_name;
339341
END IF;
@@ -372,7 +374,7 @@ BEGIN
372374
fdw_part_name := format('%s_fdw', part_name);
373375
-- Insert information about new partition in partitions table
374376
INSERT INTO shardman.partitions (part_name,node,relation) VALUES (part_name, node_id, rel_name);
375-
-- Construct name of the servers where partition will be located
377+
-- Construct name of the server where partition will be located
376378
srv_name := format('node_%s', node_id);
377379

378380
-- Replace local partition with foreign table at all nodes except owner
@@ -394,7 +396,8 @@ END
394396
$$ LANGUAGE plpgsql;
395397

396398
-- Provide requested level of redundancy. 0 means no redundancy.
397-
-- If existed level of redundancy is greater than specified, then right now this function does nothing.
399+
-- If existing level of redundancy is greater than specified, then right now this
400+
-- function does nothing.
398401
CREATE FUNCTION set_redundancy(rel regclass, redundancy int)
399402
RETURNS void AS $$
400403
DECLARE
@@ -406,7 +409,7 @@ DECLARE
406409
subs text = '';
407410
rel_name text = rel::text;
408411
BEGIN
409-
-- Loop though all partitions of this table
412+
-- Loop through all partitions of this table
410413
FOR part IN SELECT * from shardman.partitions where relation=rel_name
411414
LOOP
412415
-- Count number of replicas of this partition
@@ -425,8 +428,8 @@ BEGIN
425428
-- Establish publications and subscriptions for this partition
426429
pubs := format('%s%s:ALTER PUBLICATION node_%s ADD TABLE %I;',
427430
pubs, part.node, repl_node, part.part_name);
428-
subs := format('%s%s:ALTER SUBSCRIPTION node_%s REFRESH PUBLICATION;',
429-
subs, repl_node, part.node);
431+
subs := format('%s%s:ALTER SUBSCRIPTION node_%s_%s REFRESH PUBLICATION;',
432+
subs, repl_node, part.node, repl_node);
430433
END LOOP;
431434
END IF;
432435
END LOOP;
@@ -471,13 +474,22 @@ CREATE FUNCTION reconstruct_table_attrs(relation regclass)
471474
RETURNS text AS 'pg_shardman' LANGUAGE C STRICT;
472475

473476
-- Broadcast SQL commands to nodes and wait their completion.
474-
-- cmds is list of SQL commands separated by by semi-columns with node prefix: node-id:sql-statement;
475-
-- By default functions throws error is execution is failed at some of the nodes, with ignore_errors=true errors are ignored
476-
-- and function returns string with "Error:" prefix containing list of errors separated by semi-columns with nodes prefixes.
477-
-- In case o normal completion this function return list with node prefixes separated by semi-columns with single result of select queries
478-
-- or number of affected rows for other commands.
479-
-- If two_phase parameter is true, then each statement is wrapped in blocked and prepared with subsequent commit or rollback of prepared transaction
480-
-- at second phase of two phase commit.
477+
-- cmds is list of SQL commands separated by semi-columns with node
478+
-- prefix: node-id:sql-statement;
479+
-- To run multiple statements on node, wrap them in {}:
480+
-- {node-id:statement; statement;}
481+
-- Don't specify them separately with 2pc, we use only one prepared_xact name.
482+
-- No escaping is performed, so ';', '{' and '}' inside queries are not supported.
483+
-- By default functions throws error is execution is failed at some of the
484+
-- nodes, with ignore_errors=true errors are ignored and function returns string
485+
-- with "Error:" prefix containing list of errors separated by semicolons with
486+
-- nodes prefixes.
487+
-- In case of normal completion this function return list with node prefixes
488+
-- separated by semi-columns with single result for select queries or number of
489+
-- affected rows for other commands.
490+
-- If two_phase parameter is true, then each statement is wrapped in blocked and
491+
-- prepared with subsequent commit or rollback of prepared transaction at second
492+
-- phase of two phase commit.
481493
CREATE FUNCTION broadcast(cmds text, ignore_errors bool = false, two_phase bool = false)
482494
RETURNS text AS 'pg_shardman' LANGUAGE C STRICT;
483495

@@ -547,4 +559,3 @@ CREATE FUNCTION shardlord_connection_string()
547559
-- Check from configuration parameters is synchronous replication mode was enabled
548560
CREATE FUNCTION synchronous_replication()
549561
RETURNS bool AS 'pg_shardman' LANGUAGE C STRICT;
550-

0 commit comments

Comments
 (0)