# Mnesiac
[![Build Status](https://travis-ci.org/beardedeagle/mnesiac.svg?branch=master)](https://travis-ci.org/beardedeagle/mnesiac) [![codecov](https://codecov.io/gh/beardedeagle/mnesiac/branch/master/graph/badge.svg)](https://codecov.io/gh/beardedeagle/mnesiac) [![Hex.pm](http://img.shields.io/hexpm/v/mnesiac.svg?style=flat)](https://hex.pm/packages/mnesiac) [![Hex.pm downloads](https://img.shields.io/hexpm/dt/mnesiac.svg?style=flat)](https://hex.pm/packages/mnesiac)
Mnesia autoclustering made easy!
Docs can be found at [https://hexdocs.pm/mnesiac](https://hexdocs.pm/mnesiac).
## Installation
Simply add `mnesiac` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:mnesiac, "~> 0.3"}
]
end
```
Edit your app's config.exs to add the list of mnesia stores:
```elixir
config :mnesiac,
stores: [Mnesiac.ExampleStore, ...],
schema_type: :disc_copies, # defaults to :ram_copies
table_load_timeout: 600_000 # milliseconds, default is 600_000
```
Then add `mnesiac` to your supervision tree:
- With `libcluster` using the `Cluster.Strategy.Epmd` strategy:
```elixir
...
topology = Application.get_env(:libcluster, :topologies)
hosts = topology[:myapp][:config][:hosts]
children = [
{Cluster.Supervisor, [topology, [name: MyApp.ClusterSupervisor]]},
{Mnesiac.Supervisor, [hosts, [name: MyApp.MnesiacSupervisor]]},
...
]
...
```
- Without `libcluster`:
```elixir
...
children = [
{
Mnesiac.Supervisor,
[
[:"test01@127.0.0.1", :"test02@127.0.0.1"],
[name: MyApp.MnesiacSupervisor]
]
},
...
]
...
```
## Usage
### Table creation
Create a table store, `use Mnesiac.Store`, and add it to your app's config.exs.
All stores *MUST* implement its own `store_options/0`, which returns a keyword list of table options.
There are three optional callbacks which can be implemented:
- `init_store/0`, which allows users to implement custom table initialisation logic.
- `copy_store/0`, which allows users to implement a custom call to copy a store.
- `resolve_conflict/1`, which allows a user to implement logic when table data is found on both the remote node and local node when connecting to a cluster. This currently has no default implementation.
```elixir
defmodule MyApp.ExampleStore do
@moduledoc false
require Record
use Mnesiac.Store
Record.defrecord(
:example,
__MODULE__,
id: nil,
topic_id: nil,
event: nil
)
@type example ::
record(
:example,
id: String.t(),
topic_id: String.t(),
event: String.t()
)
@impl true
def store_options,
do: [
attributes: example() |> example() |> Keyword.keys(),
index: [:topic_id],
ram_copies: [node()]
]
end
```
### Clustering
If you are using `libcluster` or another clustering library just ensure that clustering library starts earlier than `mnesiac`. That's all, you don't need to do anything else.
If you are not using `libcluster` or similar clustering library then:
- When a node joins to an erlang/elixir cluster, run the `Mnesiac.init_mnesia()` function on the *new node*. This will initialize and copy table contents from the other online nodes.
## Development
Ensure you have the proper language versions installed. To do this, an `asdf` tools file is provided. Run the following:
```shell
git clone https://github.com/beardedeagle/mnesiac.git
git checkout -b MyFeature
asdf install
mix local.hex --force
mix local.rebar --force
mix deps.get --force
mix deps.compile --force
mix compile --force
mix check
```
**_NOTICE:_** You can find the `asdf` tool [here][1].
## Testing
Before you run any tests, ensure that you have cleaned up mnesia:
```shell
mix purge.db
```
Test results and coverage reports are generated by running the following:
```shell
mix coveralls.html --trace --slowest 10 --no-start
```
## Notice
This library was built standing on the shoulders of giants. A big thanks goes out to Mustafa Turan. The original library this was forked from can be found here: <https://github.com/mustafaturan/mnesiam>.
Happy coding!
[1]: https://github.com/asdf-vm/asdf