Add cache for first page of uncles

pull/2733/head
pasqu4le 5 years ago
parent 70bceea089
commit c83c0d39c7
No known key found for this signature in database
GPG Key ID: 8F3EE01F1DC90687
  1. 1
      CHANGELOG.md
  2. 2
      apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs
  3. 2
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  4. 4
      apps/explorer/config/config.exs
  5. 6
      apps/explorer/lib/explorer/application.ex
  6. 48
      apps/explorer/lib/explorer/chain.ex
  7. 48
      apps/explorer/lib/explorer/chain/cache/uncles.ex
  8. 3
      apps/explorer/lib/explorer/chain/import/runner/blocks.ex
  9. 28
      apps/explorer/test/explorer/chain/cache/uncles_test.exs
  10. 7
      apps/indexer/lib/indexer/block/fetcher.ex
  11. 3
      apps/indexer/lib/indexer/fetcher/uncle_block.ex
  12. 2
      apps/indexer/lib/indexer/temporary/uncles_without_index.ex

@ -1,6 +1,7 @@
## Current ## Current
### Features ### Features
- [#2733](https://github.com/poanetwork/blockscout/pull/2733) - Add cache for first page of uncles
- [#2735](https://github.com/poanetwork/blockscout/pull/2735) - Add pending transactions cache - [#2735](https://github.com/poanetwork/blockscout/pull/2735) - Add pending transactions cache
- [#2726](https://github.com/poanetwork/blockscout/pull/2726) - Remove internal_transaction block_number setting from blocks runner - [#2726](https://github.com/poanetwork/blockscout/pull/2726) - Remove internal_transaction block_number setting from blocks runner
- [#2717](https://github.com/poanetwork/blockscout/pull/2717) - Improve speed of nonconsensus data removal - [#2717](https://github.com/poanetwork/blockscout/pull/2717) - Improve speed of nonconsensus data removal

@ -5,6 +5,8 @@ defmodule BlockScoutWeb.BlockControllerTest do
setup do setup do
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
:ok :ok
end end

@ -11,6 +11,8 @@ defmodule BlockScoutWeb.ChainControllerTest do
setup do setup do
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id())
Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id())
start_supervised!(AddressesCounter) start_supervised!(AddressesCounter)
AddressesCounter.consolidate() AddressesCounter.consolidate()

@ -149,6 +149,10 @@ config :explorer, Explorer.Chain.Cache.PendingTransactions,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false), ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5)) global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
config :explorer, Explorer.Chain.Cache.Uncles,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

@ -15,7 +15,8 @@ defmodule Explorer.Application do
NetVersion, NetVersion,
PendingTransactions, PendingTransactions,
TransactionCount, TransactionCount,
Transactions Transactions,
Uncles
} }
alias Explorer.Chain.Supply.RSK alias Explorer.Chain.Supply.RSK
@ -53,7 +54,8 @@ defmodule Explorer.Application do
con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)), con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)),
Transactions, Transactions,
Accounts, Accounts,
PendingTransactions PendingTransactions,
Uncles
] ]
children = base_children ++ configurable_children() children = base_children ++ configurable_children()

@ -55,7 +55,8 @@ defmodule Explorer.Chain do
Blocks, Blocks,
PendingTransactions, PendingTransactions,
TransactionCount, TransactionCount,
Transactions Transactions,
Uncles
} }
alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner
@ -1344,20 +1345,43 @@ defmodule Explorer.Chain do
paging_options = Keyword.get(options, :paging_options) || @default_paging_options paging_options = Keyword.get(options, :paging_options) || @default_paging_options
block_type = Keyword.get(options, :block_type, "Block") block_type = Keyword.get(options, :block_type, "Block")
if block_type == "Block" && !paging_options.key do cond do
case Blocks.take_enough(paging_options.page_size) do block_type == "Block" && !paging_options.key ->
nil -> block_from_cache(block_type, paging_options, necessity_by_association)
elements = fetch_blocks(block_type, paging_options, necessity_by_association)
Blocks.update(elements) block_type == "Uncle" && !paging_options.key ->
uncles_from_cache(block_type, paging_options, necessity_by_association)
elements true ->
fetch_blocks(block_type, paging_options, necessity_by_association)
end
end
blocks -> defp block_from_cache(block_type, paging_options, necessity_by_association) do
blocks case Blocks.take_enough(paging_options.page_size) do
end nil ->
else elements = fetch_blocks(block_type, paging_options, necessity_by_association)
fetch_blocks(block_type, paging_options, necessity_by_association)
Blocks.update(elements)
elements
blocks ->
blocks
end
end
def uncles_from_cache(block_type, paging_options, necessity_by_association) do
case Uncles.take_enough(paging_options.page_size) do
nil ->
elements = fetch_blocks(block_type, paging_options, necessity_by_association)
Uncles.update(elements)
elements
blocks ->
blocks
end end
end end

@ -0,0 +1,48 @@
defmodule Explorer.Chain.Cache.Uncles do
@moduledoc """
Caches the last known uncles
"""
alias Explorer.Chain.Block
alias Explorer.Repo
use Explorer.Chain.OrderedCache,
name: :uncles,
max_size: 60,
ids_list_key: "uncle_numbers",
preload: :transactions,
preload: [miner: :names],
preload: :rewards,
preload: :nephews,
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
import Ecto.Query
@type element :: Block.t()
@type id :: non_neg_integer()
def element_to_id(%Block{number: number}), do: number
def update_from_second_degree_relations(second_degree_relations) when is_nil(second_degree_relations), do: :ok
def update_from_second_degree_relations(second_degree_relations) do
uncle_hashes =
second_degree_relations
|> Enum.map(& &1.uncle_hash)
|> Enum.uniq()
query =
from(
block in Block,
where: block.consensus == false and block.hash in ^uncle_hashes,
inner_join: nephews in assoc(block, :nephews),
preload: [nephews: block]
)
query
|> Repo.all()
|> update()
end
end

@ -612,7 +612,8 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
b in Block.SecondDegreeRelation, b in Block.SecondDegreeRelation,
join: s in subquery(query), join: s in subquery(query),
on: b.nephew_hash == s.nephew_hash and b.uncle_hash == s.uncle_hash, on: b.nephew_hash == s.nephew_hash and b.uncle_hash == s.uncle_hash,
update: [set: [uncle_fetched_at: ^updated_at]] update: [set: [uncle_fetched_at: ^updated_at]],
select: map(b, [:nephew_hash, :uncle_hash, :index])
) )
try do try do

@ -0,0 +1,28 @@
defmodule Explorer.Chain.Cache.UnclesTest do
use Explorer.DataCase
alias Explorer.Chain.Cache.Uncles
alias Explorer.Repo
setup do
Supervisor.terminate_child(Explorer.Supervisor, Uncles.child_id())
Supervisor.restart_child(Explorer.Supervisor, Uncles.child_id())
:ok
end
describe "update_from_second_degree_relations/1" do
test "fetches an uncle from a second_degree_relation and adds it to the cache" do
block = insert(:block)
uncle = insert(:block, consensus: false)
uncle_hash = uncle.hash
second_degree_relation = insert(:block_second_degree_relation, uncle_hash: uncle_hash, nephew: block)
Uncles.update_from_second_degree_relations([second_degree_relation])
assert [%{hash: uncle_hash}] = Uncles.all()
end
end
end

@ -13,7 +13,7 @@ defmodule Indexer.Block.Fetcher do
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.{Address, Block, Hash, Import, Transaction} alias Explorer.Chain.{Address, Block, Hash, Import, Transaction}
alias Explorer.Chain.Cache.Blocks, as: BlocksCache alias Explorer.Chain.Cache.Blocks, as: BlocksCache
alias Explorer.Chain.Cache.{Accounts, BlockNumber, PendingTransactions, Transactions} alias Explorer.Chain.Cache.{Accounts, BlockNumber, PendingTransactions, Transactions, Uncles}
alias Indexer.Block.Fetcher.Receipts alias Indexer.Block.Fetcher.Receipts
alias Indexer.Fetcher.{ alias Indexer.Fetcher.{
@ -177,6 +177,7 @@ defmodule Indexer.Block.Fetcher do
update_block_cache(inserted[:blocks]) update_block_cache(inserted[:blocks])
update_transactions_cache(inserted[:transactions], inserted[:fork_transactions]) update_transactions_cache(inserted[:transactions], inserted[:fork_transactions])
update_addresses_cache(inserted[:addresses]) update_addresses_cache(inserted[:addresses])
update_uncles_cache(inserted[:block_second_degree_relations])
result result
else else
{step, {:error, reason}} -> {:error, {step, reason}} {step, {:error, reason}} -> {:error, {step, reason}}
@ -204,6 +205,10 @@ defmodule Indexer.Block.Fetcher do
defp update_addresses_cache(addresses), do: Accounts.drop(addresses) defp update_addresses_cache(addresses), do: Accounts.drop(addresses)
defp update_uncles_cache(updated_relations) do
Uncles.update_from_second_degree_relations(updated_relations)
end
def import( def import(
%__MODULE__{broadcast: broadcast, callback_module: callback_module} = state, %__MODULE__{broadcast: broadcast, callback_module: callback_module} = state,
options options

@ -12,7 +12,7 @@ defmodule Indexer.Fetcher.UncleBlock do
alias Ecto.Changeset alias Ecto.Changeset
alias EthereumJSONRPC.Blocks alias EthereumJSONRPC.Blocks
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Chain.Cache.{Accounts, PendingTransactions} alias Explorer.Chain.Cache.{Accounts, PendingTransactions, Uncles}
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Indexer.{Block, BufferedTask, Tracer} alias Indexer.{Block, BufferedTask, Tracer}
alias Indexer.Fetcher.UncleBlock alias Indexer.Fetcher.UncleBlock
@ -129,6 +129,7 @@ defmodule Indexer.Fetcher.UncleBlock do
}) do }) do
{:ok, imported} -> {:ok, imported} ->
Accounts.drop(imported[:addresses]) Accounts.drop(imported[:addresses])
Uncles.update_from_second_degree_relations(imported[:block_second_degree_relations])
retry(errors) retry(errors)
{:error, {:import = step, [%Changeset{} | _] = changesets}} -> {:error, {:import = step, [%Changeset{} | _] = changesets}} ->

@ -15,6 +15,7 @@ defmodule Indexer.Temporary.UnclesWithoutIndex do
alias EthereumJSONRPC.Blocks alias EthereumJSONRPC.Blocks
alias Explorer.{Chain, Repo} alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.SecondDegreeRelation alias Explorer.Chain.Block.SecondDegreeRelation
alias Explorer.Chain.Cache.Uncles
alias Indexer.{BufferedTask, Tracer} alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.UncleBlock alias Indexer.Fetcher.UncleBlock
@ -99,6 +100,7 @@ defmodule Indexer.Temporary.UnclesWithoutIndex do
case Chain.import(%{block_second_degree_relations: %{params: block_second_degree_relations_params}}) do case Chain.import(%{block_second_degree_relations: %{params: block_second_degree_relations_params}}) do
{:ok, %{block_second_degree_relations: block_second_degree_relations}} -> {:ok, %{block_second_degree_relations: block_second_degree_relations}} ->
UncleBlock.async_fetch_blocks(block_second_degree_relations) UncleBlock.async_fetch_blocks(block_second_degree_relations)
Uncles.update_from_second_degree_relations(block_second_degree_relations)
retry(errors) retry(errors)

Loading…
Cancel
Save