1 |
|
%% Copyright (c) 2022 Peter Morgan <peter.james.morgan@gmail.com> |
2 |
|
%% |
3 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
4 |
|
%% you may not use this file except in compliance with the License. |
5 |
|
%% You may obtain a copy of the License at |
6 |
|
%% |
7 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
8 |
|
%% |
9 |
|
%% Unless required by applicable law or agreed to in writing, software |
10 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
11 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 |
|
%% See the License for the specific language governing permissions and |
13 |
|
%% limitations under the License. |
14 |
|
|
15 |
|
|
16 |
|
-module(pgmp_mm_bootstrap). |
17 |
|
|
18 |
|
|
19 |
|
-export([callback_mode/0]). |
20 |
|
-export([handle_event/4]). |
21 |
|
-export([terminate/3]). |
22 |
|
-import(pgmp_codec, [marshal/2]). |
23 |
|
-import(pgmp_codec, [size_inclusive/1]). |
24 |
|
-import(pgmp_statem, [nei/1]). |
25 |
|
-include_lib("kernel/include/logger.hrl"). |
26 |
|
|
27 |
|
|
28 |
|
callback_mode() -> |
29 |
132 |
[handle_event_function, state_enter]. |
30 |
|
|
31 |
|
|
32 |
|
terminate(Reason, State, Data) -> |
33 |
:-( |
pgmp_mm_common:terminate(Reason, State, Data). |
34 |
|
|
35 |
|
|
36 |
|
handle_event({call, _}, {request, _}, unready, Data) -> |
37 |
61 |
{next_state, starting, Data, [postpone, nei(startup)]}; |
38 |
|
|
39 |
|
handle_event({call, From}, |
40 |
|
{request, _}, |
41 |
|
startup_failure, |
42 |
|
#{errors := Errors}) -> |
43 |
:-( |
{keep_state_and_data, {reply, From, [Errors]}}; |
44 |
|
|
45 |
|
handle_event({call, _}, {request, _}, _, _) -> |
46 |
122 |
{keep_state_and_data, postpone}; |
47 |
|
|
48 |
|
handle_event(internal, peer, _, Data) -> |
49 |
66 |
case pgmp_sup:get_child(hd(get('$ancestors')), socket) of |
50 |
|
{_, PID, worker, _} when is_pid(PID) -> |
51 |
66 |
{keep_state, |
52 |
|
Data#{socket => PID}, |
53 |
|
nei(eager_startup_for_replication)}; |
54 |
|
|
55 |
|
{_, _, _, _} = Reason -> |
56 |
:-( |
{stop, Reason}; |
57 |
|
|
58 |
|
false -> |
59 |
:-( |
{stop, peer_not_found} |
60 |
|
end; |
61 |
|
|
62 |
|
handle_event(internal, |
63 |
|
join = EventName, |
64 |
|
_, |
65 |
|
#{requests := Requests, |
66 |
|
config := #{scope := Scope, |
67 |
|
group := Group} = Config} = Data) -> |
68 |
61 |
pg:join(Scope, Group, self()), |
69 |
61 |
{keep_state, |
70 |
|
Data#{requests := pgmp_connection:join( |
71 |
|
#{group => Group, |
72 |
|
server_ref => pgmp_connection:server_ref(Config), |
73 |
|
requests => Requests})}, |
74 |
|
nei({telemetry, |
75 |
|
EventName, |
76 |
|
#{count => 1}, |
77 |
|
#{group => Group}})}; |
78 |
|
|
79 |
|
handle_event(internal, join, _, #{config := #{}}) -> |
80 |
5 |
keep_state_and_data; |
81 |
|
|
82 |
|
handle_event(internal, |
83 |
|
types_when_ready, |
84 |
|
_, |
85 |
|
#{requests := Requests, config := Config} = Data) -> |
86 |
66 |
{keep_state, |
87 |
|
Data#{requests := pgmp_types:when_ready( |
88 |
|
#{requests => Requests, |
89 |
|
server_ref => pgmp_types:server_ref(Config)})}}; |
90 |
|
|
91 |
|
handle_event(internal, |
92 |
|
eager_startup_for_replication, |
93 |
|
_, |
94 |
|
#{config := #{replication := <<"false">>}}) -> |
95 |
61 |
keep_state_and_data; |
96 |
|
|
97 |
|
handle_event(internal, |
98 |
|
eager_startup_for_replication, |
99 |
|
_, |
100 |
|
_) -> |
101 |
5 |
{keep_state_and_data, nei(startup)}; |
102 |
|
|
103 |
|
handle_event(internal, startup, _, _) -> |
104 |
66 |
{keep_state_and_data, |
105 |
|
nei({send, size_inclusive([marshal(int32, 80877103)])})}; |
106 |
|
|
107 |
|
handle_event(internal, {recv, {ssl, false}}, _, _) -> |
108 |
:-( |
{keep_state_and_data, nei({startup, #{}})}; |
109 |
|
|
110 |
|
handle_event(internal, {recv, {ssl, true}}, _, _) -> |
111 |
66 |
{keep_state_and_data, nei({upgrade, #{}})}; |
112 |
|
|
113 |
|
handle_event(internal, {response, #{label := upgrade, reply := ok}}, _, _) -> |
114 |
66 |
{keep_state_and_data, nei({startup, #{}})}; |
115 |
|
|
116 |
|
handle_event(internal, |
117 |
|
{startup = EventName, KV}, |
118 |
|
_, |
119 |
|
#{config := #{user := User, |
120 |
|
database := Database, |
121 |
|
replication := Replication}}) -> |
122 |
66 |
{keep_state_and_data, |
123 |
|
[nei({send, |
124 |
|
size_inclusive( |
125 |
|
[marshal(int32, version()), |
126 |
|
maps:fold( |
127 |
|
fun |
128 |
|
(K, V, A) -> |
129 |
198 |
[marshal(string, K), marshal(string, V) | A] |
130 |
|
end, |
131 |
|
[], |
132 |
|
maps:merge( |
133 |
|
#{<<"user">> => User, |
134 |
|
<<"database">> => Database, |
135 |
|
<<"replication">> => Replication}, |
136 |
|
KV)), |
137 |
|
marshal(byte, <<0>>)])}), |
138 |
|
nei({telemetry, |
139 |
|
EventName, |
140 |
|
#{count => 1}, |
141 |
|
#{user => User, |
142 |
|
database => Database}})]}; |
143 |
|
|
144 |
|
handle_event(internal, |
145 |
|
{recv = EventName, |
146 |
|
{authentication = Tag, authenticated = Type}}, State, Data) |
147 |
|
when State == unready; State == starting -> |
148 |
:-( |
{next_state, |
149 |
|
authenticated, |
150 |
|
Data, |
151 |
|
nei({telemetry, EventName, #{count => 1}, #{tag => Tag, type => Type}})}; |
152 |
|
|
153 |
|
handle_event(internal, |
154 |
|
{recv, {ready_for_query, _} = TM}, |
155 |
|
authenticated, |
156 |
|
#{config := #{replication := Replication}} = Data) -> |
157 |
66 |
{next_state, TM, Data, nei({replication, Replication})}; |
158 |
|
|
159 |
|
handle_event(internal, {replication = EventName, Type}, _, _) -> |
160 |
66 |
{keep_state_and_data, |
161 |
|
[{change_callback_module, bootstrap_complete_callback_module(Type)}, |
162 |
|
nei({telemetry, EventName, #{count => 1}, #{type => Type}}), |
163 |
|
nei(bootstrap_complete)]}; |
164 |
|
|
165 |
|
handle_event(internal, |
166 |
|
{recv = EventName, |
167 |
|
{authentication = Tag, |
168 |
|
{sasl = Type, _} = SASL}}, |
169 |
|
_, |
170 |
|
_) -> |
171 |
66 |
{keep_state_and_data, |
172 |
|
[{push_callback_module, pgmp_mm_auth_sasl}, |
173 |
|
nei({telemetry, EventName, #{count => 1}, #{tag => Tag, type => Type}}), |
174 |
|
nei(SASL)]}; |
175 |
|
|
176 |
|
handle_event(internal, |
177 |
|
{recv = EventName, |
178 |
|
{authentication = Tag, |
179 |
|
{md5_password = Type, _} = MD5}}, |
180 |
|
_, |
181 |
|
_) -> |
182 |
:-( |
{keep_state_and_data, |
183 |
|
[{push_callback_module, pgmp_mm_auth_md5}, |
184 |
|
nei({telemetry, EventName, #{count => 1}, #{tag => Tag, type => Type}}), |
185 |
|
nei(MD5)]}; |
186 |
|
|
187 |
|
handle_event(internal, |
188 |
|
{recv = EventName, {backend_key_data = Tag, [PID, Key]}}, |
189 |
|
_, |
190 |
|
Data) -> |
191 |
66 |
{keep_state, |
192 |
|
Data#{backend => #{pid => PID, key => Key}}, |
193 |
|
nei({telemetry, EventName, #{count => 1}, #{tag => Tag}})}; |
194 |
|
|
195 |
|
handle_event(EventType, EventContent, State, Data) -> |
196 |
4093 |
pgmp_mm_common:handle_event(EventType, |
197 |
|
EventContent, |
198 |
|
State, |
199 |
|
Data). |
200 |
|
|
201 |
|
|
202 |
|
version() -> |
203 |
66 |
<<Version:32>> = <<(pgmp_config:protocol(major)):16, |
204 |
|
(pgmp_config:protocol(minor)):16>>, |
205 |
66 |
Version. |
206 |
|
|
207 |
|
|
208 |
|
bootstrap_complete_callback_module(<<"false">>) -> |
209 |
61 |
pgmp_mm_squery; |
210 |
|
|
211 |
|
bootstrap_complete_callback_module(<<"database">>) -> |
212 |
5 |
pgmp_mm_rep_log; |
213 |
|
|
214 |
|
bootstrap_complete_callback_module(Physical) when Physical == <<"true">>; |
215 |
|
Physical == <<"on">>; |
216 |
|
Physical == <<"yes">>; |
217 |
|
Physical == <<"1">> -> |
218 |
:-( |
pgmp_mm_rep_phy. |