From 7f8a78107614b37ed6677dcec7f753921473f740 Mon Sep 17 00:00:00 2001 From: beardedeagle Date: Fri, 5 May 2023 23:41:43 -0500 Subject: [PATCH] Enumerable fix for :badrpc --- CHANGELOG.md | 12 ++++++- lib/mnesiac/store_manager.ex | 67 ++++++++++++++++++++++-------------- mix.exs | 2 +- test/store_manager_test.exs | 10 ++++++ 4 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 test/store_manager_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index abee1aa..926a2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [[0.3.11]] - 2023-05-04 +### ADDED +- Added test to ensure `get_table_cookies/1` returns error when node is not reachable. + +### Fixed +- Fixed handling of `:badrpc` errors in `copy_tables/1` and `get_table_cookies/1` not being enumerable. + ## [[0.3.10]] - 2023-05-04 ### Changed -- Changed `get_table_cookies/1` to use `:local_tables` instead of `:tables` to properly identify table copies that don't exist locally to a given node. - Assert that `Mnesiac.init_mnesia/1` is called successfully. - Updated dependencies. - Updated GitHub repo files. +### FIXED +- Updated `get_table_cookies/1` to use `:local_tables` instead of `:tables` to properly identify table copies that don't exist locally to a given node, closes #84. + ## [[0.3.9]] - 2021-02-21 ### Changed - Bumped OTP version. @@ -99,6 +108,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release. +[0.3.11]: https://github.com/beardedeagle/mnesiac/compare/v0.3.10...v0.3.11 [0.3.10]: https://github.com/beardedeagle/mnesiac/compare/v0.3.9...v0.3.10 [0.3.9]: https://github.com/beardedeagle/mnesiac/compare/v0.3.8...v0.3.9 [0.3.8]: https://github.com/beardedeagle/mnesiac/compare/v0.3.7...v0.3.8 diff --git a/lib/mnesiac/store_manager.ex b/lib/mnesiac/store_manager.ex index 1cdcaca..44be0a3 100644 --- a/lib/mnesiac/store_manager.ex +++ b/lib/mnesiac/store_manager.ex @@ -50,29 +50,30 @@ defmodule Mnesiac.StoreManager do Copy tables """ def copy_tables(cluster_node) do - local_cookies = get_table_cookies() - remote_cookies = get_table_cookies(cluster_node) - - Enum.each(stores(), fn data_mapper -> - cookie = Keyword.get(data_mapper.store_options(), :record_name, data_mapper) - - case {local_cookies[cookie], remote_cookies[cookie]} do - {nil, nil} -> - apply(data_mapper, :init_store, []) - - {nil, _} -> - apply(data_mapper, :copy_store, []) - - {_, nil} -> - Logger.info("[mnesiac:#{node()}] #{inspect(data_mapper)}: no remote data to copy found.") - {:error, :no_remote_data_to_copy} - - {_local, _remote} -> - apply(data_mapper, :resolve_conflict, [cluster_node]) - end - end) - - :ok + with {:ok, local_cookies} <- get_table_cookies(), + {:ok, remote_cookies} <- get_table_cookies(cluster_node) do + Enum.each(stores(), fn data_mapper -> + case {local_cookies[data_mapper], remote_cookies[data_mapper]} do + {nil, nil} -> + apply(data_mapper, :init_store, []) + + {nil, _} -> + apply(data_mapper, :copy_store, []) + + {_, nil} -> + Logger.info("[mnesiac:#{node()}] #{inspect(data_mapper)}: no remote data to copy found.") + {:error, :no_remote_data_to_copy} + + {_local, _remote} -> + apply(data_mapper, :resolve_conflict, [cluster_node]) + end + end) + + :ok + else + {:error, reason} -> + {:error, reason} + end end @doc """ @@ -125,10 +126,24 @@ defmodule Mnesiac.StoreManager do This function returns a map of tables and their cookies. """ def get_table_cookies(node \\ node()) do - tables = :rpc.call(node, :mnesia, :system_info, [:local_tables]) + case :rpc.call(node, :mnesia, :system_info, [:local_tables], 5_000) do + {:badrpc, reason} -> + {:error, reason} - Enum.reduce(tables, %{}, fn t, acc -> - Map.put(acc, t, :rpc.call(node, :mnesia, :table_info, [t, :cookie])) + tables -> + get_table_cookies(node, tables) + end + end + + defp get_table_cookies(node, tables) do + Enum.reduce_while(tables, {:ok, %{}}, fn table, {:ok, acc} -> + case :rpc.call(node, :mnesia, :table_info, [table, :cookie], 5_000) do + {:badrpc, reason} -> + {:halt, {:error, reason}} + + cookie -> + {:cont, {:ok, Map.put(acc, table, cookie)}} + end end) end end diff --git a/mix.exs b/mix.exs index c867fdc..f46e445 100644 --- a/mix.exs +++ b/mix.exs @@ -6,7 +6,7 @@ defmodule Mnesiac.MixProject do def project do [ app: :mnesiac, - version: "0.3.10", + version: "0.3.11", elixir: "~> 1.8", elixirc_paths: elixirc_paths(Mix.env()), test_coverage: [tool: ExCoveralls], diff --git a/test/store_manager_test.exs b/test/store_manager_test.exs new file mode 100644 index 0000000..96b2bc3 --- /dev/null +++ b/test/store_manager_test.exs @@ -0,0 +1,10 @@ +defmodule StoreManagerTest do + @moduledoc false + use ExUnit.Case + + describe "get_table_cookies" do + test "returns an error when the node is not reachable" do + assert {:error, _} = Mnesiac.StoreManager.get_table_cookies(:missing_node@missing_host) + end + end +end