From 903d322553a64f20ddac31c7bfbab119a09cd5b9 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 21 Dec 2018 08:40:10 -0600 Subject: [PATCH] Use index and COUNT(*) for address_to_validation_count BlockValidationCounter is not needed once the query is switched to `COUNT(*)` and an index is added for `blocks.miner_hash`. Creating the index on eth60-test took only 12 seconds. ``` 2018-12-21T08:32:46.375 application=ecto_sql [info] == Running 20181221143000 Explorer.Repo.Migrations.CreateBlocksMinerHashIndex.change/0 forward 2018-12-21T08:32:46.375 application=ecto_sql [info] create index blocks_miner_hash_index 2018-12-21T08:32:59.211 application=ecto_sql [info] == Migrated 20181221143000 in 12.8s ``` Before the index both `COUNT(*)` and `COUNT(hash)` (the old usage before 76fc8e03775fd36e770927e7edfd17495ac58098 in 92f99cac220069a3519daa0816811ba3565f0e91) take > 800ms, which would have a noticable impact on the UI. ``` sql> SELECT COUNT(*) FROM blocks WHERE blocks.miner_hash = ( SELECT blocks.miner_hash FROM blocks LIMIT 1 ) [2018-12-21 08:27:43] 1 row retrieved starting from 1 in 906 ms (execution: 889 ms, fetching: 17 ms) sql> SELECT COUNT(hash) FROM blocks WHERE blocks.miner_hash = ( SELECT blocks.miner_hash FROM blocks LIMIT 1 ) [2018-12-21 08:28:04] 1 row retrieved starting from 1 in 819 ms (execution: 811 ms, fetching: 8 ms) ``` After the index both queries benefited because `COUNT(hash)` was able to use Bitmap Index Scan, but `COUNT(*)` was much better using a normal Index Scan: ``` sql> SELECT COUNT(hash) FROM blocks WHERE blocks.miner_hash = ( SELECT blocks.miner_hash FROM blocks LIMIT 1 ) [2018-12-21 08:33:43] 1 row retrieved starting from 1 in 776 ms (execution: 768 ms, fetching: 8 ms) sql> SELECT COUNT(*) FROM blocks WHERE blocks.miner_hash = ( SELECT blocks.miner_hash FROM blocks LIMIT 1 ) [2018-12-21 08:33:55] 1 row retrieved starting from 1 in 130 ms (execution: 120 ms, fetching: 10 ms) ``` The `SELECT` to get a miner_hash takes 54ms alone, so the `COUNT(*)` takes ~70ms, but EXPLAINs take just as long so ~50ms is my latency to eth60-test, meaning the `SELECT COUNT(*)` takes about 20ms plus latency. --- .../address_contract_controller_test.exs | 7 +- .../controllers/address_controller_test.exs | 6 +- ...s_internal_transaction_controller_test.exs | 7 +- .../address_read_contract_controller_test.exs | 8 +- .../address_token_controller_test.exs | 13 +- .../address_transaction_controller_test.exs | 7 +- .../address_contract_verification_test.exs | 4 - .../features/viewing_addresses_test.exs | 48 +------- .../features/viewing_chain_test.exs | 5 +- .../features/viewing_transactions_test.exs | 7 +- apps/explorer/config/config.exs | 2 - apps/explorer/config/test.exs | 4 - apps/explorer/lib/explorer/application.ex | 1 - apps/explorer/lib/explorer/chain.ex | 5 +- .../counters/block_validation_counter.ex | 115 ------------------ ...1143000_create_blocks_miner_hash_index.exs | 7 ++ .../block_validation_counter_test.exs | 45 ------- 17 files changed, 19 insertions(+), 272 deletions(-) delete mode 100644 apps/explorer/lib/explorer/counters/block_validation_counter.ex create mode 100644 apps/explorer/priv/repo/migrations/20181221143000_create_blocks_miner_hash_index.exs delete mode 100644 apps/explorer/test/explorer/counters/block_validation_counter_test.exs diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs index eed61473b9..3e3c92cb7f 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs @@ -1,12 +1,9 @@ defmodule BlockScoutWeb.AddressContractControllerTest do - use BlockScoutWeb.ConnCase, - # ETS table is shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.ConnCase, async: true import BlockScoutWeb.Router.Helpers, only: [address_contract_path: 3] alias Explorer.Chain.Hash - alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token alias Explorer.Factory @@ -47,8 +44,6 @@ defmodule BlockScoutWeb.AddressContractControllerTest do created_contract_address: address ) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_contract_path(BlockScoutWeb.Endpoint, :index, address)) assert html_response(conn, 200) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs index 5a002fcde6..e4e25174b1 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs @@ -3,7 +3,7 @@ defmodule BlockScoutWeb.AddressControllerTest do # ETS tables are shared in `Explorer.Counters.*` async: false - alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} + alias Explorer.Counters.AddressesWithBalanceCounter describe "GET index/2" do test "returns top addresses", %{conn: conn} do @@ -15,8 +15,6 @@ defmodule BlockScoutWeb.AddressControllerTest do start_supervised!(AddressesWithBalanceCounter) AddressesWithBalanceCounter.consolidate() - start_supervised!(BlockValidationCounter) - conn = get(conn, address_path(conn, :index)) assert conn.assigns.address_tx_count_pairs @@ -31,8 +29,6 @@ defmodule BlockScoutWeb.AddressControllerTest do start_supervised!(AddressesWithBalanceCounter) AddressesWithBalanceCounter.consolidate() - start_supervised!(BlockValidationCounter) - conn = get(conn, address_path(conn, :index)) assert html_response(conn, 200) =~ address_name.name diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs index 75d84d966a..6ce66a1e2e 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs @@ -1,13 +1,10 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do - use BlockScoutWeb.ConnCase, - # ETS table is shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.ConnCase, async: true import BlockScoutWeb.Router.Helpers, only: [address_internal_transaction_path: 3, address_internal_transaction_path: 4] alias Explorer.Chain.{Block, InternalTransaction, Transaction} - alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/3" do @@ -28,8 +25,6 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do test "includes USD exchange rate value for address in assigns", %{conn: conn} do address = insert(:address) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert %Token{} = conn.assigns.exchange_rate diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs index f65d8a4d32..40e0c5b3db 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs @@ -1,9 +1,6 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do - use BlockScoutWeb.ConnCase, - # ETS table is shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.ConnCase, async: true - alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/3" do @@ -26,9 +23,6 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do transaction = insert(:transaction, from_address: contract_address) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - insert( :internal_transaction_create, index: 0, diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs index 5efd4b3edd..0b4008611f 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs @@ -1,12 +1,9 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do - use BlockScoutWeb.ConnCase, - # ETS table is shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.ConnCase, async: true import BlockScoutWeb.Router.Helpers, only: [address_token_path: 3] alias Explorer.Chain.{Token} - alias Explorer.Counters.BlockValidationCounter describe "GET index/2" do test "with invalid address hash", %{conn: conn} do @@ -60,8 +57,6 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do to_address: address ) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_token_path(conn, :index, address)) actual_token_hashes = @@ -103,8 +98,6 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do %Token{name: name, type: type, inserted_at: inserted_at} = token - start_supervised!(BlockValidationCounter) - conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), %{ "token_name" => name, @@ -136,8 +129,6 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) end) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert conn.assigns.next_page_params @@ -148,8 +139,6 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do token = insert(:token) insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash)) refute conn.assigns.next_page_params diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs index d21495b0eb..028387501a 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs @@ -1,12 +1,9 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do - use BlockScoutWeb.ConnCase, - # ETS table is shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.ConnCase, async: true import BlockScoutWeb.Router.Helpers, only: [address_transaction_path: 3, address_transaction_path: 4] alias Explorer.Chain.Transaction - alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/2" do @@ -50,8 +47,6 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do test "includes USD exchange rate value for address in assigns", %{conn: conn} do address = insert(:address) - start_supervised!(BlockValidationCounter) - conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert %Token{} = conn.assigns.exchange_rate diff --git a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs index 6704f76486..97a8c9e11b 100644 --- a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs @@ -2,7 +2,6 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do use BlockScoutWeb.FeatureCase, async: true alias BlockScoutWeb.{AddressContractPage, ContractVerifyPage} - alias Explorer.Counters.BlockValidationCounter alias Explorer.Factory alias Plug.Conn @@ -30,9 +29,6 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do transaction: transaction ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressContractPage.visit_page(address) |> AddressContractPage.click_verify_and_publish() diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs index 8821e42122..16711b6230 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs @@ -3,7 +3,7 @@ defmodule BlockScoutWeb.ViewingAddressesTest do # Because ETS tables is shared for `Explorer.Counters.*` async: false - alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} + alias Explorer.Counters.AddressesWithBalanceCounter alias BlockScoutWeb.{AddressPage, AddressView, Notifier} setup do @@ -41,9 +41,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do [first_address | _] = addresses [last_address | _] = Enum.reverse(addresses) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - start_supervised!(AddressesWithBalanceCounter) AddressesWithBalanceCounter.consolidate() @@ -57,9 +54,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do test "viewing address overview information", %{session: session} do address = insert(:address, fetched_coin_balance: 500) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(address) |> assert_text(AddressPage.balance(), "0.0000000000000005 POA") @@ -80,9 +74,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do created_contract_address: contract ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - address_hash = AddressView.trimmed_hash(address.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash) @@ -116,9 +107,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do created_contract_address: another_contract ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - contract_hash = AddressView.trimmed_hash(contract.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash) @@ -129,13 +117,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do end describe "viewing transactions" do - setup do - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - - :ok - end - test "sees all addresses transactions by default", %{ addresses: addresses, session: session, @@ -214,9 +195,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do internal_transaction_lincoln_to_address: internal_transaction, session: session } do - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(addresses.lincoln) |> AddressPage.click_internal_transactions() @@ -230,9 +208,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do |> insert(from_address: addresses.lincoln) |> with_block(insert(:block, number: 7000)) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(addresses.lincoln) |> AddressPage.click_internal_transactions() @@ -280,9 +255,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(lincoln) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -324,9 +296,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(morty) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -361,9 +330,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(lincoln) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -394,9 +360,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(lincoln) |> click(AddressPage.token_transfers_expansion(transaction)) @@ -431,9 +394,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:address_current_token_balance, address: lincoln, token_contract_address_hash: contract_address.hash) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> AddressPage.visit_page(lincoln) |> AddressPage.click_tokens() @@ -487,9 +447,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:address_current_token_balance, address: lincoln, token_contract_address_hash: contract_address_2.hash) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - {:ok, lincoln: lincoln} end @@ -535,9 +492,6 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:fetched_balance, address_hash: address.hash, value: 5, block_number: block.number) insert(:fetched_balance, address_hash: address.hash, value: 10, block_number: block_one_day_ago.number) - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - {:ok, address: address} end diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs index 15d69e712b..67e0984576 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs @@ -7,7 +7,7 @@ defmodule BlockScoutWeb.ViewingChainTest do alias BlockScoutWeb.{AddressPage, BlockPage, ChainPage, TransactionPage} alias Explorer.Chain.Block - alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} + alias Explorer.Counters.AddressesWithBalanceCounter setup do Enum.map(401..404, &insert(:block, number: &1)) @@ -35,9 +35,6 @@ defmodule BlockScoutWeb.ViewingChainTest do start_supervised!(AddressesWithBalanceCounter) AddressesWithBalanceCounter.consolidate() - start_supervised!(BlockValidationCounter) - BlockValidationCounter.consolidate_blocks() - session |> ChainPage.visit_page() |> ChainPage.search(to_string(address.hash)) diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs index a63b283fa4..1fd14622cb 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs @@ -1,13 +1,10 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do @moduledoc false - use BlockScoutWeb.FeatureCase, - # ETS tables are shared in `Explorer.Counters.BlockValidationCounter` - async: false + use BlockScoutWeb.FeatureCase, async: true alias BlockScoutWeb.{AddressPage, TransactionListPage, TransactionLogsPage, TransactionPage} alias Explorer.Chain.Wei - alias Explorer.Counters.BlockValidationCounter setup do block = @@ -142,8 +139,6 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do session: session, transaction: transaction } do - start_supervised!(BlockValidationCounter) - session |> TransactionLogsPage.visit_page(transaction) |> TransactionLogsPage.click_address(lincoln) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index eb554e74c2..0c1240079e 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -15,8 +15,6 @@ config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: true, config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: true, enable_consolidation: true -config :explorer, Explorer.Counters.BlockValidationCounter, enabled: true, enable_consolidation: true - config :explorer, Explorer.ExchangeRates, enabled: true, store: :ets config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: :timer.seconds(2) diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index 29ab6b0fb6..fff39c6b25 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -15,10 +15,6 @@ config :explorer, Explorer.ExchangeRates, enabled: false, store: :ets config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: false, enable_consolidation: false -config :explorer, Explorer.Counters.BlockValidationCounter, enabled: false, enable_consolidation: true - -config :explorer, Explorer.Counters.BlockValidationCounter, enabled: false, enable_consolidation: false - config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: false, enable_consolidation: false config :explorer, Explorer.Market.History.Cataloger, enabled: false diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 7032e4c3f7..eafe31cdd4 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -36,7 +36,6 @@ defmodule Explorer.Application do configure(Explorer.ExchangeRates), configure(Explorer.Market.History.Cataloger), configure(Explorer.Counters.TokenHoldersCounter), - configure(Explorer.Counters.BlockValidationCounter), configure(Explorer.Counters.AddressesWithBalanceCounter), configure(Explorer.Validator.MetadataProcessor) ] diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index c85e9e948d..aa389cbde0 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -44,7 +44,6 @@ defmodule Explorer.Chain do alias Explorer.Counters.{ AddressesWithBalanceCounter, - BlockValidationCounter, TokenHoldersCounter } @@ -988,7 +987,9 @@ defmodule Explorer.Chain do """ @spec address_to_validation_count(Address.t()) :: non_neg_integer() def address_to_validation_count(%Address{hash: hash}) do - BlockValidationCounter.fetch(hash) + query = from(block in Block, where: block.miner_hash == ^hash, select: fragment("COUNT(*)")) + + Repo.one(query) end @doc """ diff --git a/apps/explorer/lib/explorer/counters/block_validation_counter.ex b/apps/explorer/lib/explorer/counters/block_validation_counter.ex deleted file mode 100644 index 22b3935106..0000000000 --- a/apps/explorer/lib/explorer/counters/block_validation_counter.ex +++ /dev/null @@ -1,115 +0,0 @@ -defmodule Explorer.Counters.BlockValidationCounter do - use GenServer - - @moduledoc """ - Module responsible for fetching and consolidating the number of - validations from an address. - """ - - alias Explorer.Chain - alias Explorer.Chain.Hash - - @table :block_validation_counter - - def table_name do - @table - end - - # It is undesirable to automatically start the consolidation in all environments. - # Consider the test environment: if the consolidation initiates but does not - # finish before a test ends, that test will fail. This way, hundreds of - # tests were failing before disabling the consolidation and the scheduler in - # the test env. - config = Application.get_env(:explorer, Explorer.Counters.BlockValidationCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - - @doc """ - Creates a process to continually monitor the validation counts. - """ - @spec start_link(term()) :: GenServer.on_start() - def start_link(_) do - GenServer.start_link(__MODULE__, :ok, name: __MODULE__) - end - - ## Server - @impl true - def init(args) do - create_table() - - if enable_consolidation?() do - Task.start_link(&consolidate_blocks/0) - end - - Chain.subscribe_to_events(:blocks) - - {:ok, args} - end - - def create_table do - opts = [ - :set, - :named_table, - :public, - read_concurrency: true - ] - - :ets.new(table_name(), opts) - end - - @doc """ - Consolidates the number of block validations grouped by `address_hash`. - """ - def consolidate_blocks do - Chain.each_address_block_validation_count(fn {address_hash, total} -> - insert_or_update_counter(address_hash, total) - end) - end - - @doc """ - Fetches the number of validations related to an `address_hash`. - """ - @spec fetch(Hash.Address.t()) :: non_neg_integer - def fetch(addr_hash) do - do_fetch(:ets.lookup(table_name(), to_string(addr_hash))) - end - - defp do_fetch([{_, result} | _]), do: result - defp do_fetch([]), do: 0 - - @impl true - def handle_info({:chain_event, :blocks, _type, blocks}, state) do - blocks - |> Enum.map(& &1.miner_hash) - |> Enum.each(&insert_or_update_counter(&1, 1)) - - {:noreply, state} - end - - @doc """ - Inserts a new item into the `:ets` table. - - When the record exist, the counter will be incremented by one. When the - record does not exist, the counter will be inserted with a default value. - """ - @spec insert_or_update_counter(Hash.Address.t(), non_neg_integer) :: term() - def insert_or_update_counter(addr_hash, number) do - string_addr = to_string(addr_hash) - default = {string_addr, 0} - - :ets.update_counter(table_name(), string_addr, number, default) - end - - @doc """ - Returns a boolean that indicates whether consolidation is enabled - - In order to choose whether or not to enable the scheduler and the initial - consolidation, change the following Explorer config: - - `config :explorer, Explorer.Counters.BlockValidationCounter, enable_consolidation: true` - - to: - - `config :explorer, Explorer.Counters.BlockValidationCounter, enable_consolidation: false` - """ - def enable_consolidation?, do: @enable_consolidation -end diff --git a/apps/explorer/priv/repo/migrations/20181221143000_create_blocks_miner_hash_index.exs b/apps/explorer/priv/repo/migrations/20181221143000_create_blocks_miner_hash_index.exs new file mode 100644 index 0000000000..bd59932295 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20181221143000_create_blocks_miner_hash_index.exs @@ -0,0 +1,7 @@ +defmodule Explorer.Repo.Migrations.CreateBlocksMinerHashIndex do + use Ecto.Migration + + def change do + create(index(:blocks, [:miner_hash])) + end +end diff --git a/apps/explorer/test/explorer/counters/block_validation_counter_test.exs b/apps/explorer/test/explorer/counters/block_validation_counter_test.exs deleted file mode 100644 index ac1345e2a8..0000000000 --- a/apps/explorer/test/explorer/counters/block_validation_counter_test.exs +++ /dev/null @@ -1,45 +0,0 @@ -defmodule Explorer.Counters.BlockValidationCounterTest do - use Explorer.DataCase - - alias Explorer.Counters.BlockValidationCounter - - setup do - start_supervised!(BlockValidationCounter) - - :ok - end - - describe "consolidate/0" do - test "loads the address' validations consolidated info" do - address = insert(:address) - - insert(:block, miner: address, miner_hash: address.hash) - insert(:block, miner: address, miner_hash: address.hash) - - another_address = insert(:address) - - insert(:block, miner: another_address, miner_hash: another_address.hash) - - BlockValidationCounter.consolidate_blocks() - - assert BlockValidationCounter.fetch(address.hash) == 2 - assert BlockValidationCounter.fetch(another_address.hash) == 1 - end - end - - describe "fetch/1" do - test "fetches the total block validations by a given address" do - address = insert(:address) - another_address = insert(:address) - - assert BlockValidationCounter.fetch(address.hash) == 0 - assert BlockValidationCounter.fetch(another_address.hash) == 0 - - BlockValidationCounter.insert_or_update_counter(address.hash, 1) - BlockValidationCounter.insert_or_update_counter(another_address.hash, 10) - - assert BlockValidationCounter.fetch(address.hash) == 1 - assert BlockValidationCounter.fetch(another_address.hash) == 10 - end - end -end