commit
6bb1a7bebb
@ -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…
Reference in new issue