Skip to content

Commit

Permalink
Add a tiny optimization.
Browse files Browse the repository at this point in the history
  • Loading branch information
arcusfelis committed Mar 8, 2012
1 parent 4c8f96c commit d80619f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@
*.boot
*.script
ebin/*.app
.eunit
62 changes: 32 additions & 30 deletions src/pgsql_sock.erl
Expand Up @@ -136,42 +136,44 @@ setopts(#state{mod = Mod, sock = Sock}, Opts) ->

decode(<<Type:8, Len:?int32, Rest/binary>> = Bin, #state{c = C} = State) ->
Len2 = Len - 4,
case Rest of
<<Data:Len2/binary, Tail/binary>> when Type == $N ->
gen_fsm:send_all_state_event(C, {notice, decode_error(Data)}),
decode(Tail, State);
<<Data:Len2/binary, Tail/binary>> when Type == $S ->
[Name, Value] = decode_strings(Data),
gen_fsm:send_all_state_event(C, {parameter_status, Name, Value}),
decode(Tail, State);
<<Data:Len2/binary, Tail/binary>> when Type == $E ->
gen_fsm:send_event(C, {error, decode_error(Data)}),
decode(Tail, State);
<<Data:Len2/binary, Tail/binary>> when Type == $A ->
<<Pid:?int32, Strings/binary>> = Data,
case decode_strings(Strings) of
[Channel, Payload] -> ok;
[Channel] -> Payload = <<>>
end,
gen_fsm:send_all_state_event(C, {notification, Channel, Pid, Payload}),
decode(Tail, State);
<<Data:Len2/binary, Tail/binary>> ->
gen_fsm:send_event(C, {Type, Data}),
decode(Tail, State);
_Other ->
State#state{tail = Bin}
<<Data:Len2/binary, Tail/binary>> = Rest,
case Type of
$N ->
gen_fsm:send_all_state_event(C, {notice, decode_error(Data)}),
decode(Tail, State);
$S ->
[Name, Value] = decode_strings(Data),
gen_fsm:send_all_state_event(C, {parameter_status, Name, Value}),
decode(Tail, State);
$E ->
gen_fsm:send_event(C, {error, decode_error(Data)}),
decode(Tail, State);
$A ->
<<Pid:?int32, Strings/binary>> = Data,
case decode_strings(Strings) of
[Channel, Payload] -> ok;
[Channel] -> Payload = <<>>
end,
gen_fsm:send_all_state_event(C, {notification, Channel, Pid, Payload}),
decode(Tail, State);
_ ->
gen_fsm:send_event(C, {Type, Data}),
decode(Tail, State)
end;
decode(Bin, State) ->
State#state{tail = Bin}.

%% decode a single null-terminated string
decode_string(Bin) ->
decode_string(Bin, <<>>).

decode_string(<<0, Rest/binary>>, Str) ->
{Str, Rest};
decode_string(<<C, Rest/binary>>, Str) ->
decode_string(Rest, <<Str/binary, C>>).
Idx = first_index(Bin, 0),
<<H:Idx/binary, _, T/binary>> = Bin,
{H, T}.

first_index(<<X, T/binary>>, Idx) ->
case X of
0 -> Idx;
_ -> first_index(T, Idx+1)
end.

%% decode multiple null-terminated string
decode_strings(Bin) ->
Expand Down

2 comments on commit d80619f

@mabrek
Copy link

@mabrek mabrek commented on d80619f Apr 24, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have some benchmarks or test case that show results of the optimisation?
I did something similar in https://github.com/mabrek/epgsql/blob/async/src/pgsql_wire.erl#L39 , but didn't compare decoding speed because it wasn't a bottleneck in my case.

@arcusfelis
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was something like 32% of the execution time was in the decode_stringfunction.
My code decreased it to 28%. Not so much.
I did not tested the code with binary:split, but it can be even more slow. :/

Please sign in to comment.