Skip to content

Commit

Permalink
feat: don't parse frame until its used
Browse files Browse the repository at this point in the history
Hopefully some sort of performance increase.. if the race condition can
be resolved.
  • Loading branch information
hpopp committed Dec 28, 2017
1 parent d1e9af7 commit 342e563
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 9 deletions.
19 changes: 19 additions & 0 deletions lib/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule Kadabra.Connection do
Encodable,
Error,
Frame,
FrameParser,
Hpack,
Http2,
Stream,
Expand Down Expand Up @@ -168,6 +169,24 @@ defmodule Kadabra.Connection do

# recv

def recv(frame, state) when is_binary(frame) do
case FrameParser.sid_and_type(frame) do
{0, _} ->
{:ok, f, ""} = Frame.new(frame)
mod = FrameParser.to_module(f.type)
f |> mod.new() |> recv(state)
{_, 0x5} ->
{:ok, f, ""} = Frame.new(frame)
mod = FrameParser.to_module(f.type)
f |> mod.new() |> recv(state)
{stream_id, _} ->
state.ref
|> Stream.via_tuple(stream_id)
|> Stream.cast_recv(frame)
{:noreply, [], state}
end
end

def recv(%Data{stream_id: 0}, state) do
# This is an error
{:noreply, [], state}
Expand Down
4 changes: 2 additions & 2 deletions lib/connection/socket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ defmodule Kadabra.Connection.Socket do
end

def sendf(pid, bin) do
GenServer.cast(pid, {:send, bin})
GenServer.call(pid, {:send, bin})
end

def setopts(pid, opts) do
Expand Down Expand Up @@ -180,7 +180,7 @@ defmodule Kadabra.Connection.Socket do
{:ok, frame, rest} ->
state.sup
|> Connection.via_tuple()
|> GenStage.call({:recv, frame})
|> GenStage.cast({:recv, frame})

parse_bin(socket, rest, state)

Expand Down
24 changes: 19 additions & 5 deletions lib/frame_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,31 @@ defmodule Kadabra.FrameParser do
}

def parse(bin) do
case Frame.new(bin) do
{:ok, %{type: type} = frame, rest} ->
mod = to_module(type)
f = mod.new(frame)
{:ok, f, rest}
case p(bin) do
{:ok, frame, rest} ->
{:ok, frame, rest}

{:error, bin} ->
{:error, bin}
end
end

def p(""), do: {:error, ""}
def p(<<p_size::24, type::8, f::8, 0::1, s_id::31, p::bitstring>> = bin) do
size = p_size * 8
if byte_size(bin) < (p_size + 9) do
{:error, bin}
else
f_size = size + 72
<<frame::size(f_size)>> <> rest = bin
{:ok, <<frame::size(f_size)>>, <<rest::bitstring>>}
end
end

def sid_and_type(<<_::24, type::8, _::8, 0::1, s_id::31, _::bitstring>>) do
{s_id, type}
end

def to_module(0x0), do: Data
def to_module(0x1), do: Headers
def to_module(0x3), do: RstStream
Expand Down
8 changes: 7 additions & 1 deletion lib/stream.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule Kadabra.Stream do

require Logger

alias Kadabra.{Connection, Encodable, Hpack, Http2, Stream}
alias Kadabra.{Connection, Encodable, Frame, Hpack, Http2, Stream}
alias Kadabra.Connection.{Settings, Socket}

alias Kadabra.Frame.{
Expand Down Expand Up @@ -100,6 +100,12 @@ defmodule Kadabra.Stream do
{:keep_state, %{stream | flow: flow}}
end

def recv(frame, state, stream) when is_binary(frame) do
{:ok, f, ""} = Frame.new(frame)
mod = Kadabra.FrameParser.to_module(f.type)
f |> mod.new() |> recv(state, stream)
end

def recv(%Data{end_stream: true, data: data}, state, stream)
when state in [@hc_local] do
stream = %Stream{stream | body: stream.body <> data}
Expand Down
2 changes: 1 addition & 1 deletion lib/supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ defmodule Kadabra.Supervisor do
supervisor(ConnectionSupervisor, conn_opts, id: :connection_sup)
]

supervise(children, strategy: :one_for_one)
supervise(children, strategy: :one_for_all)
end
end

0 comments on commit 342e563

Please sign in to comment.