Ecto adapter for Mnesia Erlang term database

Deps StatusHex.pm DownloadsLatest VersionLicenseBuild StatusCoverage StatusEbert

Ecto 2.X adapter for Mnesia Erlang term database. In most cases it can be used as drop-in replacement for other adapters.

Supported features:

Planned features:

Not supported features (create issue and vote if you need them):

In general. This adapter is still not passing all Ecto integration tests and in active development. But it already can be helpful in simple use-cases.

Why Mnesia?

We have a production task that needs low read-latency database and our data fits in RAM, so Mnesia is the best choice: it's part of OTP, shares same space as our app does, work fast in RAM and supports transactions (it's critical for fintech projects).

Why do we need an adapter? We don't want to lock us to any specific database, since requirements can change. Ecto allows to switch databases by simply modifying the config, and we might want to go back to Postres or another DB.

Clustering

We don't recommend using distributed Mnesia, because it's neither an AP, nor a CP database. (And there is no such thing as an AC DB.) Mnesia requires you to handle network partitions (split brains) manually.

So clustering should be an option only when you are absolutely sure about how to recover from split-brains. In general, if you are not sure what a network split is, don't use distributed Mnesia.

Mnesia configuration from config.exs

config :ecto_mnesia,
  host: {:system, :atom, "MNESIA_HOST", Kernel.node()},
  storage_type: {:system, :atom, "MNESIA_STORAGE_TYPE", :disc_copies}

config :mnesia,
  dir: 'priv/data/mnesia' # Make sure this directory exists

Notice that {:system, [TYPE], ENV_NAME, default_value} tuples can be replaced with any raw values.

They tell adapter to read configuration from environment in run-time, so you will be able to set MNESIA_HOST and MNESIA_STORAGE_TYPE environment variables, which is very useful when you releasing app in production and don't want to rebuild all code on each config change.

If you want to know more how this tool works take look at Confex package.

Storage Types

Table Types (Engines)

In migrations you can select which kind of table you want to use:

  create_if_not_exists table(:my_table, engine: :set) do
    # ...
  end

Supported types:

Ordered Set Performance

Ordered set comes in a cost of increased complexity of write operations:

Set

Operation | Average | Worst Case ----------|---------|---------- Space | O(n) | O(n) Search | O(1) | O(n) Insert | O(1) | O(n) Delete | O(1) | O(n)

Ordered Set

Operation | Average | Worst Case ----------|----------|---------- Space | O(n) | O(n) Search | O(log n) | O(n) Insert | O(log n) | O(n) Delete | O(log n) | O(n)

Installation

It is available in Hex, the package can be installed as:

  1. Add ecto_mnesia to your list of dependencies in mix.exs:
def deps do
  [{:ecto_mnesia, "~> 0.9.0"}]
end
  1. Ensure ecto_mnesia is started before your application:
def application do
  [applications: [:ecto_mnesia]]
end
  1. Use EctoMnesia.Adapter as your Ecto.Repo adapter:
config :my_app, MyRepo,
  adapter: EctoMnesia.Adapter
  1. Optionally set custom Mnesia data dir (don't forget to create it):
config :mnesia, :dir, 'priv/data/mnesia'

The docs can be found at https://hexdocs.pm/ecto_mnesia.

Thanks

We want to thank meh for his Amnesia package that helped a lot in initial Mnesia investigations. Some pieces of code was copied from his repo.

Also big thanks to josevalim for Elixir, Ecto and active help while this adapter was developed.