Merge pull request #1388 from poanetwork/ab-cache-max-min-block-number
cache max and min block numberpull/1398/head
commit
32107089d5
@ -0,0 +1,93 @@ |
|||||||
|
defmodule Explorer.Chain.BlockNumberCache do |
||||||
|
@moduledoc """ |
||||||
|
Cache for max and min block numbers. |
||||||
|
""" |
||||||
|
|
||||||
|
alias Explorer.Chain |
||||||
|
|
||||||
|
@tab :block_number_cache |
||||||
|
# 30 minutes |
||||||
|
@cache_period 1_000 * 60 * 30 |
||||||
|
@key "min_max" |
||||||
|
@opts_key "opts" |
||||||
|
|
||||||
|
@spec setup(Keyword.t()) :: :ok |
||||||
|
def setup(opts \\ []) do |
||||||
|
if :ets.whereis(@tab) == :undefined do |
||||||
|
:ets.new(@tab, [ |
||||||
|
:set, |
||||||
|
:named_table, |
||||||
|
:public, |
||||||
|
write_concurrency: true |
||||||
|
]) |
||||||
|
end |
||||||
|
|
||||||
|
setup_opts(opts) |
||||||
|
update_cache() |
||||||
|
|
||||||
|
:ok |
||||||
|
end |
||||||
|
|
||||||
|
def max_number do |
||||||
|
value(:max) |
||||||
|
end |
||||||
|
|
||||||
|
def min_number do |
||||||
|
value(:min) |
||||||
|
end |
||||||
|
|
||||||
|
def min_and_max_numbers do |
||||||
|
value(:all) |
||||||
|
end |
||||||
|
|
||||||
|
defp value(type) do |
||||||
|
initial_cache = {_min, _max, old_current_time} = cached_values() |
||||||
|
|
||||||
|
{min, max, _current_time} = |
||||||
|
if current_time() - old_current_time > cache_period() do |
||||||
|
update_cache() |
||||||
|
|
||||||
|
cached_values() |
||||||
|
else |
||||||
|
initial_cache |
||||||
|
end |
||||||
|
|
||||||
|
case type do |
||||||
|
:max -> max |
||||||
|
:min -> min |
||||||
|
:all -> {min, max} |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
defp update_cache do |
||||||
|
current_time = current_time() |
||||||
|
{min, max} = Chain.fetch_min_and_max_block_numbers() |
||||||
|
tuple = {min, max, current_time} |
||||||
|
|
||||||
|
:ets.insert(@tab, {@key, tuple}) |
||||||
|
end |
||||||
|
|
||||||
|
defp setup_opts(opts) do |
||||||
|
cache_period = opts[:cache_period] || @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 current_time do |
||||||
|
utc_now = DateTime.utc_now() |
||||||
|
|
||||||
|
DateTime.to_unix(utc_now, :millisecond) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,79 @@ |
|||||||
|
defmodule Explorer.Chain.BlockNumberCacheTest do |
||||||
|
use Explorer.DataCase |
||||||
|
|
||||||
|
alias Explorer.Chain.BlockNumberCache |
||||||
|
|
||||||
|
describe "max_number/1" do |
||||||
|
test "returns max number" do |
||||||
|
insert(:block, number: 5) |
||||||
|
|
||||||
|
BlockNumberCache.setup() |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
end |
||||||
|
|
||||||
|
test "invalidates cache if period did pass" do |
||||||
|
insert(:block, number: 5) |
||||||
|
|
||||||
|
BlockNumberCache.setup(cache_period: 2_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
|
||||||
|
insert(:block, number: 10) |
||||||
|
|
||||||
|
Process.sleep(2_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 10 |
||||||
|
assert BlockNumberCache.min_number() == 5 |
||||||
|
end |
||||||
|
|
||||||
|
test "does not invalidate cache if period time did not pass" do |
||||||
|
insert(:block, number: 5) |
||||||
|
|
||||||
|
BlockNumberCache.setup(cache_period: 10_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
|
||||||
|
insert(:block, number: 10) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "min_number/1" do |
||||||
|
test "returns max number" do |
||||||
|
insert(:block, number: 2) |
||||||
|
|
||||||
|
BlockNumberCache.setup() |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 2 |
||||||
|
end |
||||||
|
|
||||||
|
test "invalidates cache" do |
||||||
|
insert(:block, number: 5) |
||||||
|
|
||||||
|
BlockNumberCache.setup(cache_period: 2_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.min_number() == 5 |
||||||
|
|
||||||
|
insert(:block, number: 2) |
||||||
|
|
||||||
|
Process.sleep(2_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.min_number() == 2 |
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
end |
||||||
|
|
||||||
|
test "does not invalidate cache if period time did not pass" do |
||||||
|
insert(:block, number: 5) |
||||||
|
|
||||||
|
BlockNumberCache.setup(cache_period: 10_000) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
|
||||||
|
insert(:block, number: 2) |
||||||
|
|
||||||
|
assert BlockNumberCache.max_number() == 5 |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue