New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
body recursive fetch_all without Enum.reverse #205
body recursive fetch_all without Enum.reverse #205
Conversation
{:done, rows} -> | ||
case accum do | ||
[] -> {:ok, rows} | ||
accum -> {:ok, Enum.reverse(rows ++ accum)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rows should've been reversed here before concatenating, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. They should have been reversed, before appending.
And since the reason for changing
Mix.install([:benchee, :exqlite])
alias Exqlite.Sqlite3
defmodule Setup do
def create_users(conn, count) do
:ok = Sqlite3.execute(conn, "create table users (id integer primary key, name text)")
{:ok, stmt} = Sqlite3.prepare(conn, "insert into users values (?, ?)")
Sqlite3.execute(conn, "begin")
Enum.each(1..count, fn i ->
:ok = Sqlite3.bind(conn, stmt, [i, "User-" <> to_string(i)])
:done = Sqlite3.step(conn, stmt)
end)
Sqlite3.execute(conn, "commit")
end
end
defmodule Tail do
def fetch_all(conn, statement) do
fetch_all(conn, statement, 50, [])
end
defp fetch_all(conn, statement, chunk_size, accum) do
case Sqlite3.multi_step(conn, statement, chunk_size) do
{:done, rows} ->
case accum do
[] -> {:ok, rows}
accum -> {:ok, Enum.reverse(rows ++ accum)}
end
{:rows, rows} ->
fetch_all(conn, statement, chunk_size, Enum.reverse(rows) ++ accum)
{:error, reason} ->
{:error, reason}
:busy ->
{:error, "Database busy"}
end
end
end
defmodule Body do
def fetch_all(conn, statement) do
{:ok, try_fetch_all(conn, statement, 50)}
catch
:throw, {:error, _reason} = error -> error
end
defp try_fetch_all(conn, statement, chunk_size) do
case Sqlite3.multi_step(conn, statement, chunk_size) do
{:done, rows} -> rows
{:rows, rows} -> rows ++ try_fetch_all(conn, statement, chunk_size)
{:error, _reason} = error -> throw(error)
:busy -> throw({:error, "Database busy"})
end
end
end
{:ok, conn} = Sqlite3.open(":memory:")
:ok = Setup.create_users(conn, 10000)
{:ok, stmt} = Sqlite3.prepare(conn, "select * from users")
Benchee.run(
%{
"body-recursive" => fn -> Body.fetch_all(conn, stmt) end,
"tail-recursive" => fn -> Tail.fetch_all(conn, stmt) end
},
memory_time: 2
)
|
Fix released as |
Thanks for fixing this properly! Looks like the initial bottle neck was not the body recursion 😅 |
closes #204