_site/cover/msmp_debug.COVER.html

1 %% Copyright (c) 2023 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(msmp_debug).
17
18
19 -feature(maybe_expr, enable).
20
21
22 -export([binary_workflow/1]).
23 -export([packetise/2]).
24 -export([unhex/2]).
25 -export([write_file/2]).
26 -import(scran_branch, [alt/1]).
27 -import(scran_bytes, [length_encoded/1]).
28 -import(scran_combinator, [map_parser/2]).
29 -import(scran_combinator, [map_result/2]).
30 -import(scran_combinator, [peek/1]).
31 -import(scran_combinator, [rest/0]).
32 -import(scran_result, [into_map/1]).
33 -import(scran_result, [kv/2]).
34 -import(scran_sequence, [sequence/1]).
35 -include_lib("kernel/include/logger.hrl").
36
37
38 dump(Parser) ->
39
:-(
fun
40 (Input) ->
41
:-(
(into_map(
42 map_parser(
43 length_encoded(
44 map_result(
45 msmp_integer_fixed:decode(3),
46 fun
47 (Length) ->
48 %% adjust length to include the sequence number
49
:-(
Length + 1
50 end)),
51 sequence(
52 [kv(encoded,
53 map_result(
54 peek(rest()),
55 fun
56 (<<Sequence:8, Body/bytes>>) ->
57
:-(
?LOG_DEBUG(#{size => byte_size(Body),
58 sequence => Sequence,
59
:-(
packet => <<(byte_size(Body)):24/little, Sequence:8, Body/bytes>>}),
60
:-(
<<(byte_size(Body)):24/little, Sequence:8, Body/bytes>>
61 end)),
62 kv(sequence, msmp_integer_fixed:decode(1)),
63 kv(packet, Parser)]))))(Input)
64 end.
65
66 parser(BinLog, ClientFlags) ->
67
:-(
fun
68 (Input) ->
69
:-(
(alt([msmp_binlog_network_stream:decode(BinLog),
70 msmp_binlog_dump:decode(),
71 msmp_binlog_dump_gtid:decode(),
72 msmp_handshake:decode(),
73 msmp_handshake_response:decode(),
74 msmp_packet_ok:decode(ClientFlags),
75 msmp_packet_error:decode(ClientFlags),
76 msmp_com_query:decode(ClientFlags),
77 msmp_packet_eof:decode(ClientFlags),
78 msmp_ssl_request:decode(),
79 %% msmp_auth_more_data:decode(),
80 msmp_register_replica:decode(),
81 otherwise()]))(Input)
82 end.
83
84 otherwise() ->
85
:-(
fun
86 (Input) ->
87
:-(
(into_map(sequence([kv(otherwise, rest())])))(Input)
88 end.
89
90
91 repeated(BinLog, ClientFlags) ->
92
:-(
fun
93 (Input) ->
94
:-(
(?FUNCTION_NAME(BinLog, ClientFlags, []))(Input)
95 end.
96
97
98 repeated(#{mapped := Mapped} = BinLog, ClientFlags, A) ->
99
:-(
fun
100 (Input) ->
101 %% ?LOG_DEBUG(#{input => Input, a_length => length(A)}),
102
103
:-(
case (dump(parser(BinLog, ClientFlags)))(Input) of
104 {Remaining,
105 #{packet := #{action := handshake,
106 capability_flags_1 := Flags1,
107 capability_flags_2 := Flags2}} = Packet} ->
108
:-(
?LOG_DEBUG(#{packet => Packet}),
109
:-(
(?FUNCTION_NAME(
110 BinLog,
111 maps:merge(Flags1, Flags2),
112 [Packet | A]))
113 (Remaining);
114
115 {Remaining,
116 #{packet := #{action := handshake_response,
117 client_flags := Flags}} = Packet} ->
118
:-(
?LOG_DEBUG(#{packet => Packet}),
119
:-(
(?FUNCTION_NAME(
120 BinLog,
121 Flags,
122 [Packet | A]))
123 (Remaining);
124
125 {Remaining,
126 #{packet := #{action := log_event,
127 header := #{event_type := table_map},
128 event := #{table_id := TableId} = Event}} = Packet} ->
129
:-(
?LOG_DEBUG(#{packet => Packet}),
130
:-(
(?FUNCTION_NAME(
131 BinLog#{mapped := Mapped#{TableId => maps:without([table_id], Event)}},
132 ClientFlags,
133 [Packet | A]))
134 (Remaining);
135
136 {Remaining, #{} = Packet} ->
137
:-(
?LOG_DEBUG(#{packet => Packet}),
138
:-(
(?FUNCTION_NAME(
139 BinLog,
140 ClientFlags,
141 [Packet | A]))
142 (Remaining);
143
144 nomatch when A == [] ->
145
:-(
nomatch;
146
147 nomatch ->
148
:-(
{Input, lists:reverse(A)}
149 end
150 end.
151
152
153 write_file(In, Out) ->
154
:-(
{ok, Packets} = file:consult(In),
155
156
:-(
ClientFlags = #{protocol_41 => true,
157 session_track => true,
158 transactions => true},
159
160
:-(
BinLog = #{mapped => #{}},
161
162
:-(
{<<>>, Decoded} = (repeated(
163 BinLog,
164 ClientFlags))
165 (iolist_to_binary(
166
:-(
[Data || {frame, Data} <- Packets])),
167
:-(
{ok, Header} = file:read_file("HEADER.terms"),
168
:-(
ok = write_terms(Out, Header, Decoded).
169
170
171 write_terms(Filename, Header, Terms) ->
172
:-(
file:write_file(
173 Filename,
174 [Header,
175 "\n",
176 lists:map(
177 fun
178 (Term) ->
179
:-(
io_lib:format("~p.~n~n", [Term])
180 end,
181 Terms)]).
182
183
184 packetise(In, Out) ->
185
:-(
{ok, Packets} = file:consult(In),
186
:-(
{ok, Header} = file:read_file("HEADER.terms"),
187
188
:-(
write_terms(
189 Out,
190 Header,
191 lists:reverse(
192 frames(iolist_to_binary(
193 lists:filtermap(
194 fun
195 (#{packet := #{ip := #{tcp := #{data := Data}}}}) when Data /= <<>> ->
196
:-(
{true, Data};
197
198 (_) ->
199
:-(
false
200 end,
201 Packets))))).
202
203
204 unhex(In, Out) ->
205
:-(
{ok, Hexed} = file:read_file(In),
206
:-(
{ok, Header} = file:read_file("HEADER.terms"),
207
:-(
write_terms(
208 Out,
209 Header,
210 lists:reverse(
211 frames(
212 iolist_to_binary(
213
:-(
[binary:decode_hex(Hex) || Hex <- binary:split(Hexed, <<"\n">>, [global,trim_all])])))).
214
215 binary_workflow(In) ->
216
:-(
ok = unhex(In ++ ".binary", In ++ ".terms"),
217
:-(
ok = write_file(In ++ ".terms", In ++ "-msmp-debug.terms").
218
219
220 frames(Frames) ->
221
:-(
?FUNCTION_NAME(Frames, []).
222
223 frames(<<Length:24/little, SeqBody:(Length + 1)/bytes, Remainder/bytes>>, A) ->
224
:-(
?FUNCTION_NAME(Remainder,
225 [{frame, <<Length:24/little, SeqBody:(Length + 1)/bytes>>} | A]);
226 frames(<<>>, A) ->
227
:-(
A;
228
229 frames(Remainder, A) ->
230
:-(
[{remaining, Remainder} | A].
Line Hits Source