Calculate indexed ratio in SQL

By calculating the indexed ratio in SQL, we only have 1 round trip to
the database instead of 1 to get the max and 1 to get the min.
pull/1332/head
Luke Imhoff 6 years ago
parent 083e5d3278
commit cb7bc384e8
  1. 7
      apps/block_scout_web/lib/block_scout_web/counters/blocks_indexed_counter.ex
  2. 10
      apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs
  3. 28
      apps/explorer/lib/explorer/chain.ex
  4. 6
      apps/explorer/test/explorer/chain_test.exs

@ -39,10 +39,9 @@ defmodule BlockScoutWeb.Counters.BlocksIndexedCounter do
ratio = Chain.indexed_ratio()
finished? =
if ratio < 1 do
false
else
Chain.finished_indexing?()
case Decimal.cmp(ratio, 1) do
:lt -> false
_ -> Chain.finished_indexing?()
end
Notifier.broadcast_blocks_indexed_ratio(ratio, finished?)

@ -20,7 +20,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index)
end
assert Explorer.Chain.indexed_ratio() == 0.5
assert Decimal.cmp(Explorer.Chain.indexed_ratio(), Decimal.from_float(0.5)) == :eq
session
|> AppPage.visit_page()
@ -32,7 +32,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index)
end
assert Explorer.Chain.indexed_ratio() == 1.0
assert Decimal.cmp(Explorer.Chain.indexed_ratio(), 1) == :eq
session
|> AppPage.visit_page()
@ -46,7 +46,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
BlocksIndexedCounter.calculate_blocks_indexed()
assert Explorer.Chain.indexed_ratio() == 0.5
assert Decimal.cmp(Explorer.Chain.indexed_ratio(), Decimal.from_float(0.5)) == :eq
session
|> AppPage.visit_page()
@ -66,7 +66,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
BlocksIndexedCounter.calculate_blocks_indexed()
assert Explorer.Chain.indexed_ratio() == 0.9
assert Decimal.cmp(Explorer.Chain.indexed_ratio(), Decimal.from_float(0.9)) == :eq
session
|> AppPage.visit_page()
@ -87,7 +87,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
BlocksIndexedCounter.calculate_blocks_indexed()
assert Explorer.Chain.indexed_ratio() == 1.0
assert Decimal.cmp(Explorer.Chain.indexed_ratio(), 1) == :eq
session
|> AppPage.visit_page()

@ -835,23 +835,31 @@ defmodule Explorer.Chain do
...> insert(:block, number: index)
...> end
iex> Explorer.Chain.indexed_ratio()
0.5
Decimal.new(1, 50000000000000000000, -20)
If there are no blocks, the percentage is 0.
iex> Explorer.Chain.indexed_ratio()
0
Decimal.new(0)
"""
@spec indexed_ratio() :: float()
@spec indexed_ratio() :: Decimal.t()
def indexed_ratio do
with {:ok, min_block_number} <- consensus_block_number(:min),
{:ok, max_block_number} <- consensus_block_number(:max) do
indexed_blocks = max_block_number - min_block_number + 1
indexed_blocks / (max_block_number + 1)
else
{:error, _} -> 0
end
# subquery so we need to cast less
decimal_min_max_query =
from(block in Block,
select: %{min_number: type(min(block.number), :decimal), max_number: type(max(block.number), :decimal)},
where: block.consensus == true
)
query =
from(decimal_min_max in subquery(decimal_min_max_query),
# math on `NULL` returns `NULL` so `coalesce` works as expected
select:
coalesce((decimal_min_max.max_number - decimal_min_max.min_number + 1) / (decimal_min_max.max_number + 1), 0)
)
Repo.one!(query)
end
@doc """

@ -921,11 +921,11 @@ defmodule Explorer.ChainTest do
insert(:block, number: index)
end
assert 0.5 == Chain.indexed_ratio()
assert Decimal.cmp(Chain.indexed_ratio(), Decimal.from_float(0.5)) == :eq
end
test "returns 0 if no blocks" do
assert 0 == Chain.indexed_ratio()
assert Decimal.new(0) == Chain.indexed_ratio()
end
test "returns 1.0 if fully indexed blocks" do
@ -933,7 +933,7 @@ defmodule Explorer.ChainTest do
insert(:block, number: index)
end
assert 1.0 == Chain.indexed_ratio()
assert Decimal.cmp(Chain.indexed_ratio(), 1) == :eq
end
end

Loading…
Cancel
Save