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

Commit 05a0f09

Browse files
committed
part table in progress
1 parent 1381ad6 commit 05a0f09

9 files changed

+319
-81
lines changed

bin/common.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ set -e
66

77
pgpath=~/postgres/install/vanilla/
88
pathmanpath=~/postgres/pg_pathman
9+
install_pathman=false
910

1011
master_datadir=~/postgres/data1
1112
master_port=5432
1213

1314
# declare -a worker_datadirs=()
1415
# declare -a worker_ports=()
15-
declare -a worker_datadirs=("${HOME}/postgres/data2")
16-
declare -a worker_ports=("5433")
17-
# declare -a worker_datadirs=("${HOME}/postgres/data2" "${HOME}/postgres/data3")
18-
# declare -a worker_ports=("5433" "5434")
16+
# declare -a worker_datadirs=("${HOME}/postgres/data2")
17+
# declare -a worker_ports=("5433")
18+
declare -a worker_datadirs=("${HOME}/postgres/data2" "${HOME}/postgres/data3")
19+
declare -a worker_ports=("5433" "5434")
1920

2021
#------------------------------------------------------------
2122
PATH="$PATH:${pgpath}bin/"

bin/shardman_init.sh

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
script_dir=`dirname "$(readlink -f "$0")"`
44
source "${script_dir}/common.sh"
55

6-
echo $PATH
7-
cd $pathmanpath
8-
USE_PGXS=1 make install
6+
if $install_pathman; then
7+
cd $pathmanpath
8+
USE_PGXS=1 make clean
9+
USE_PGXS=1 make install
10+
fi
911

1012
cd "${script_dir}/.."
1113
make clean
@@ -18,8 +20,10 @@ for datadir in $master_datadir "${worker_datadirs[@]}"; do
1820
initdb -D "$datadir"
1921
done
2022

23+
cat postgresql.conf.common.template >> ${master_datadir}/postgresql.conf
2124
cat postgresql.conf.master.template >> ${master_datadir}/postgresql.conf
2225
for worker_datadir in "${worker_datadirs[@]}"; do
26+
cat postgresql.conf.common.template >> ${worker_datadir}/postgresql.conf
2327
cat postgresql.conf.worker.template >> ${worker_datadir}/postgresql.conf
2428
done
2529

@@ -30,3 +34,9 @@ for port in $master_port "${worker_ports[@]}"; do
3034
done
3135

3236
restart_nodes
37+
38+
psql -p 5433 -c "CREATE TABLE partitioned_table(id INT NOT NULL, payload REAL);"
39+
psql -p 5433 -c "INSERT INTO partitioned_table SELECT generate_series(1, 1000), random();"
40+
psql -c "select shardman.add_node('port=5433');"
41+
42+
psql

pg_shardman--0.0.1.sql

Lines changed: 114 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ END
1414
$$;
1515

1616
-- active is the normal mode, others needed only for proper node add and removal
17-
CREATE TYPE node_status AS ENUM ('active', 'add_in_progress', 'rm_in_progress');
17+
CREATE TYPE worker_node_status AS ENUM ('active', 'add_in_progress', 'rm_in_progress');
1818

1919
-- list of nodes present in the cluster
2020
CREATE TABLE nodes (
2121
id serial PRIMARY KEY,
22-
connstring text,
23-
status node_status NOT NULL
22+
connstring text NOT NULL UNIQUE,
23+
worker_status worker_node_status,
24+
-- While currently we don't support master and worker roles on one node,
25+
-- potentially node can be either worker, master or both, so we need 3 bits.
26+
-- One bool with NULL might be fine, but it seems a bit counter-intuitive.
27+
worker bool NOT NULL DEFAULT true,
28+
master bool NOT NULL DEFAULT false
2429
);
2530

2631
-- Master is removing us, so reset our state, removing all subscriptions. A bit
@@ -33,13 +38,65 @@ BEGIN
3338
PERFORM shardman.pg_shardman_cleanup(false);
3439
RETURN NULL;
3540
END
36-
$$ language plpgsql;
41+
$$ LANGUAGE plpgsql;
3742
CREATE TRIGGER rm_node_worker_side AFTER UPDATE ON shardman.nodes
38-
FOR EACH ROW WHEN (OLD.status = 'active' AND NEW.status = 'rm_in_progress')
43+
FOR EACH ROW WHEN (OLD.worker_status = 'active' AND NEW.worker_status = 'rm_in_progress')
3944
EXECUTE PROCEDURE rm_node_worker_side();
4045
-- fire trigger only on worker nodes
4146
ALTER TABLE shardman.nodes ENABLE REPLICA TRIGGER rm_node_worker_side;
4247

48+
-- sharded tables
49+
CREATE TABLE tables (
50+
relation text PRIMARY KEY, -- table name
51+
expr text NOT NULL,
52+
partitions_count int NOT NULL,
53+
create_sql text NOT NULL, -- sql to create the table
54+
-- Node on which table was partitioned at the beginning. Used only during
55+
-- initial tables inflation to distinguish between table owner and other
56+
-- nodes, probably cleaner keep it in separate table.
57+
initial_node int NOT NULL REFERENCES nodes(id)
58+
);
59+
60+
-- On adding new table, create it on non-owner nodes using provided sql and
61+
-- partition
62+
CREATE FUNCTION new_table_worker_side() RETURNS TRIGGER AS $$
63+
BEGIN
64+
IF NEW.initial_node != (SELECT shardman.get_node_id()) THEN
65+
EXECUTE format('%s', NEW.create_sql);
66+
EXECUTE format('select create_hash_partitions(%L, %L, %L);',
67+
NEW.relation, NEW.expr, NEW.partitions_count);
68+
END IF;
69+
RETURN NULL;
70+
END
71+
$$ LANGUAGE plpgsql;
72+
CREATE TRIGGER new_table_worker_side AFTER INSERT ON shardman.tables
73+
FOR EACH ROW EXECUTE PROCEDURE new_table_worker_side();
74+
-- fire trigger only on worker nodes
75+
ALTER TABLE shardman.tables ENABLE REPLICA TRIGGER new_table_worker_side;
76+
-- On master side, insert partitions
77+
CREATE FUNCTION new_table_master_side() RETURNS TRIGGER AS $$
78+
BEGIN
79+
INSERT INTO shardman.partitions
80+
-- part names look like tablename_partnum, partnums start from 0
81+
SELECT NEW.relation || '_' || range.num AS part_name,
82+
NEW.relation AS relation,
83+
NEW.initial_node AS owner
84+
FROM
85+
(SELECT num FROM generate_series(0, NEW.partitions_count, 1)
86+
AS range(num)) AS range;
87+
RETURN NULL;
88+
END
89+
$$ LANGUAGE plpgsql;
90+
CREATE TRIGGER new_table_master_side AFTER INSERT ON shardman.tables
91+
FOR EACH ROW EXECUTE PROCEDURE new_table_master_side();
92+
93+
CREATE TABLE partitions (
94+
part_name text PRIMARY KEY,
95+
relation text NOT NULL REFERENCES tables(relation),
96+
owner int REFERENCES nodes(id) -- node on which partition lies
97+
);
98+
99+
43100
-- Currently it is used just to store node id, in general we can keep any local
44101
-- node metadata here. If is ever used extensively, probably hstore suits better.
45102
CREATE TABLE local_meta (
@@ -88,12 +145,44 @@ CREATE TABLE cmd_opts (
88145

89146
-- Internal functions
90147

148+
-- Called on shardmaster bgw start. Add itself to nodes table, set id, create
149+
-- publication.
150+
CREATE FUNCTION master_boot() RETURNS void AS $$
151+
DECLARE
152+
-- If we have never booted as a master before, we have a work to do
153+
init_master bool DEFAULT false;
154+
master_connstring text;
155+
master_id int;
156+
BEGIN
157+
raise INFO 'Booting master';
158+
PERFORM shardman.create_meta_pub();
159+
160+
master_id := shardman.get_node_id();
161+
IF master_id IS NULL THEN
162+
SELECT pg_settings.setting into master_connstring from pg_settings
163+
WHERE NAME = 'shardman.master_connstring';
164+
EXECUTE format(
165+
'INSERT INTO @extschema@.nodes VALUES (DEFAULT, %L, NULL, false, true)
166+
RETURNING id', master_connstring) INTO master_id;
167+
PERFORM shardman.set_node_id(master_id);
168+
init_master := true;
169+
ELSE
170+
EXECUTE 'SELECT NOT (SELECT master FROM shardman.nodes WHERE id = $1)'
171+
INTO init_master USING master_id;
172+
EXECUTE 'UPDATE shardman.nodes SET master = true WHERE id = $1' USING master_id;
173+
END IF;
174+
IF init_master THEN
175+
-- TODO: set up lr channels
176+
END IF;
177+
END $$ LANGUAGE plpgsql;
178+
91179
-- These tables will be replicated to worker nodes, notifying them about changes.
92180
-- Called on master.
93181
CREATE FUNCTION create_meta_pub() RETURNS void AS $$
94182
BEGIN
95183
IF NOT EXISTS (SELECT * FROM pg_publication WHERE pubname = 'shardman_meta_pub') THEN
96-
CREATE PUBLICATION shardman_meta_pub FOR TABLE shardman.nodes;
184+
CREATE PUBLICATION shardman_meta_pub FOR TABLE
185+
shardman.nodes, shardman.tables;
97186
END IF;
98187
END;
99188
$$ LANGUAGE plpgsql;
@@ -111,24 +200,6 @@ BEGIN
111200
END;
112201
$$ LANGUAGE plpgsql;
113202

114-
-- If for cmd cmd_id we haven't yet inserted new node, do that; mark it as passive
115-
-- for now, we still need to setup lr and set its id on the node itself
116-
-- Return generated or existing node id
117-
CREATE FUNCTION insert_node(connstring text, cmd_id bigint) RETURNS int AS $$
118-
DECLARE
119-
n_id int;
120-
BEGIN
121-
SELECT node_id FROM @extschema@.cmd_log INTO n_id WHERE id = cmd_id;
122-
IF n_id IS NULL THEN
123-
INSERT INTO @extschema@.nodes
124-
VALUES (DEFAULT, quote_literal(connstring), 'add_in_progress')
125-
RETURNING id INTO n_id;
126-
UPDATE @extschema@.cmd_log SET node_id = n_id WHERE id = cmd_id;
127-
END IF;
128-
RETURN n_id;
129-
END
130-
$$ LANGUAGE plpgsql;
131-
132203
-- Create logical pgoutput replication slot, if not exists
133204
CREATE FUNCTION create_repslot(slot_name text) RETURNS void AS $$
134205
DECLARE
@@ -213,7 +284,25 @@ CREATE FUNCTION set_node_id(node_id int) RETURNS void AS $$
213284
UPDATE @extschema@.local_meta SET v = node_id WHERE k = 'node_id';
214285
$$ LANGUAGE sql;
215286

216-
CREATE FUNCTION gen_create_table_sql(relation text) RETURNS text
287+
-- If for cmd cmd_id we haven't yet inserted new node, do that; mark it as passive
288+
-- for now, we still need to setup lr and set its id on the node itself
289+
-- Return generated or existing node id
290+
CREATE FUNCTION insert_node(connstring text, cmd_id bigint) RETURNS int AS $$
291+
DECLARE
292+
n_id int;
293+
BEGIN
294+
SELECT node_id FROM @extschema@.cmd_log INTO n_id WHERE id = cmd_id;
295+
IF n_id IS NULL THEN
296+
INSERT INTO @extschema@.nodes
297+
VALUES (DEFAULT, connstring, 'add_in_progress')
298+
RETURNING id INTO n_id;
299+
UPDATE @extschema@.cmd_log SET node_id = n_id WHERE id = cmd_id;
300+
END IF;
301+
RETURN n_id;
302+
END
303+
$$ LANGUAGE plpgsql;
304+
305+
CREATE FUNCTION gen_create_table_sql(relation text, connstring text) RETURNS text
217306
AS 'pg_shardman' LANGUAGE C;
218307

219308
-- Interface functions

postgresql.conf.common.template

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
shared_preload_libraries = 'pg_pathman, pg_shardman'
2+
3+
log_min_messages = INFO
4+
# client_min_messages = NOTICE
5+
client_min_messages = INFO
6+
7+
wal_level = logical

postgresql.conf.master.template

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
log_min_messages = INFO
2-
client_min_messages = NOTICE
3-
4-
# for logical repl
5-
wal_level = logical
6-
7-
shared_preload_libraries='pg_pathman, pg_shardman'
8-
1+
# master-specific part
92
shardman.master = on
103
shardman.master_dbname = ars
4+
shardman.master_connstring = 'port=5432'

postgresql.conf.worker.template

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1 @@
1-
shared_preload_libraries = 'pg_pathman, pg_shardman'
2-
3-
log_min_messages = INFO
4-
client_min_messages = NOTICE
5-
6-
wal_level = logical
7-
81
# worker-specific part
9-
shardman.master_connsting = 'port=5432'

readme.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ shared_preload_libraries = '$libdir/pg_shardman'
1313
restart postgres server and run
1414
drop extension if exists pg_shardman;
1515
create extension pg_shardman;
16+
17+
The master itself can't be worker node for now, because it requires special
18+
handling of LR channels setup.

0 commit comments

Comments
 (0)