Merge pull request #1848 from poanetwork/block_counter_cache

Add cache for block counter
master-1.3.12 v1.3.11-beta
Victor Baranov 6 years ago committed by GitHub
commit 5c53ceedf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  2. 3
      apps/explorer/config/config.exs
  3. 3
      apps/explorer/lib/explorer/application.ex
  4. 13
      apps/explorer/lib/explorer/chain.ex
  5. 84
      apps/explorer/lib/explorer/chain/block_count_cache.ex
  6. 45
      apps/explorer/test/explorer/chain/block_count_cache_test.exs

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.ChainController do
alias BlockScoutWeb.ChainView
alias Explorer.{Chain, PagingOptions, Repo}
alias Explorer.Chain.{Address, Block, Transaction}
alias Explorer.Chain.{Address, Block, BlockCountCache, Transaction}
alias Explorer.Counters.AverageBlockTime
alias Explorer.ExchangeRates.Token
alias Explorer.Market
@ -11,7 +11,7 @@ defmodule BlockScoutWeb.ChainController do
def show(conn, _params) do
transaction_estimated_count = Chain.transaction_estimated_count()
block_count = Chain.block_consensus_count()
block_count = BlockCountCache.count()
exchange_rate = Market.get_exchange_rate(Explorer.coin()) || Token.null()

@ -78,6 +78,9 @@ config :spandex_ecto, SpandexEcto.EctoLogger,
tracer: Explorer.Tracer,
otp_app: :explorer
config :explorer, Explorer.Chain.BlockCountCache,
ttl: System.get_env("BLOCK_COUNT_CACHE_TTL")
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

@ -6,7 +6,7 @@ defmodule Explorer.Application do
use Application
alias Explorer.Admin
alias Explorer.Chain.{BlockNumberCache, TransactionCountCache}
alias Explorer.Chain.{BlockCountCache, BlockNumberCache, TransactionCountCache}
alias Explorer.Repo.PrometheusLogger
@impl Application
@ -38,6 +38,7 @@ defmodule Explorer.Application do
res = Supervisor.start_link(children, opts)
BlockNumberCache.setup()
BlockCountCache.setup()
res
end

@ -1042,7 +1042,7 @@ defmodule Explorer.Chain do
end
end
@spec fetch_min_and_max_block_numbers() :: {non_neg_integer(), non_neg_integer}
@spec fetch_min_and_max_block_numbers() :: {non_neg_integer, non_neg_integer}
def fetch_min_and_max_block_numbers do
query =
from(block in Block,
@ -1058,6 +1058,17 @@ defmodule Explorer.Chain do
end
end
@spec fetch_count_consensus_block() :: non_neg_integer
def fetch_count_consensus_block do
query =
from(block in Block,
select: count(block.hash),
where: block.consensus == true
)
Repo.one!(query)
end
@doc """
The number of `t:Explorer.Chain.InternalTransaction.t/0`.

@ -0,0 +1,84 @@
defmodule Explorer.Chain.BlockCountCache do
@moduledoc """
Cache for count consensus blocks.
"""
alias Explorer.Chain
@tab :block_count_cache
# 1 minutes
@cache_period 1_000 * 60
@key "count"
@opts_key "opts"
@spec setup() :: :ok
def setup do
if :ets.whereis(@tab) == :undefined do
:ets.new(@tab, [
:set,
:named_table,
:public,
write_concurrency: true
])
end
setup_opts()
update_cache()
:ok
end
def count do
initial_cache = {_count, old_current_time} = cached_values()
{count, _current_time} =
if current_time() - old_current_time > cache_period() do
update_cache()
cached_values()
else
initial_cache
end
count
end
defp update_cache do
current_time = current_time()
count = count_from_db()
tuple = {count, current_time}
:ets.insert(@tab, {@key, tuple})
end
defp setup_opts do
cache_period = Application.get_env(:explorer, __MODULE__)[:ttl] || @cache_period
:ets.insert(@tab, {@opts_key, cache_period})
end
defp cached_values do
[{_, cached_values}] = :ets.lookup(@tab, @key)
cached_values
end
defp cache_period do
[{_, cache_period}] = :ets.lookup(@tab, @opts_key)
cache_period
end
defp count_from_db do
Chain.fetch_count_consensus_block()
rescue
_e ->
0
end
defp current_time do
utc_now = DateTime.utc_now()
DateTime.to_unix(utc_now, :millisecond)
end
end

@ -0,0 +1,45 @@
defmodule Explorer.Chain.BlockCountCacheTest do
use Explorer.DataCase
alias Explorer.Chain.BlockCountCache
describe "count/0" do
test "return count" do
insert(:block, number: 1, consensus: true)
insert(:block, number: 2, consensus: true)
insert(:block, number: 3, consensus: false)
BlockCountCache.setup()
assert BlockCountCache.count() == 2
end
test "invalidates cache if period did pass" do
insert(:block, number: 1, consensus: true)
Application.put_env(:explorer, BlockCountCache, ttl: 2_00)
BlockCountCache.setup()
assert BlockCountCache.count() == 1
insert(:block, number: 2, consensus: true)
Process.sleep(2_000)
assert BlockCountCache.count() == 2
end
test "does not invalidate cache if period time did not pass" do
insert(:block, number: 1, consensus: true)
Application.put_env(:explorer, BlockCountCache, ttl: 2_00)
BlockCountCache.setup()
assert BlockCountCache.count() == 1
insert(:block, number: 2, consensus: true)
assert BlockCountCache.count() == 1
end
end
end
Loading…
Cancel
Save